有什么区别 constreadonly 你使用其中一种而不是另一种吗?

有帮助吗?

解决方案

除了明显的差异之外

  • 必须在定义时声明值 const VS readonly 值可以动态计算,但需要在构造函数退出之前分配。之后它被冻结。
  • 'const 是隐式的 static. 。你用一个 ClassName.ConstantName 符号来访问它们。

有一个细微的差别。考虑一个定义在 AssemblyA.

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyB 参考 AssemblyA 并在代码中使用这些值。当这个被编译时,

  • 在这种情况下 const value,它就像一个查找替换,值 2 被“烘焙”到 AssemblyB的IL。这意味着如果明天我更新 I_CONST_VALUE 到未来20个。 AssemblyB 在我重新编译之前仍然有 2.
  • 在这种情况下 readonly 值,它就像一个 ref 到一个内存位置。该值没有被烘焙到 AssemblyB的IL。这意味着如果内存位置被更新, AssemblyB 无需重新编译即可获取新值。因此,如果 I_RO_VALUE 更新到30,只需要构建 AssemblyA. 。所有客户端都不需要重新编译。

因此,如果您确信常量的值不会改变,请使用 const.

public const int CM_IN_A_METER = 100;

但如果你有一个可能会改变的常数(例如w.r.t.精确)..或者当有疑问时,使用 readonly.

public readonly float PI = 3.14;

更新:阿库需要被提及,因为他首先指出了这一点。我还需要插入我学到的地方.. 有效的 C# - 比尔·瓦格纳

其他提示

常量有一个陷阱!如果您引用另一个程序集中的常量,则其值将直接编译到调用程序集中。这样,当您更新引用的程序集中的常量时,它不会在调用程序集中发生更改!

常数

  • 常量默认是静态的
  • 它们必须在编译时具有值(您可以有例如3.14 * 2,但不能调用方法)
  • 可以在函数内声明
  • 被复制到使用它们的每个程序集中(每个程序集都会获取值的本地副本)
  • 可以用在属性中

只读实例字段

  • 构造函数退出时必须已设置值
  • 创建实例时进行评估

静态只读字段

  • 当代码执行命中类引用时进行评估(当创建新实例或执行静态方法时)
  • 静态构造函数完成时必须有一个评估值
  • 不建议将 ThreadStaticAttribute 放在这些属性上(静态构造函数将仅在一个线程中执行,并将为其线程设置值;所有其他线程都将具有未初始化的该值)

只是补充一下,引用类型的 ReadOnly 仅使引用只读,而不是值。例如:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

这解释了它. 。概括:const 必须在声明时初始化,readonly 可以在构造函数上初始化(因此根据所使用的构造函数具有不同的值)。

编辑:请参阅上面 Gishu 的陷阱以了解细微的差异

const: :任何地方都无法改变。

readonly: :该值只能在构造函数中更改。在正常功能中无法更改。

只读有一个小问题。只读字段可以在构造函数中多次设置。即使该值是在两个不同的链式构造函数中设置的,它仍然是允许的。


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

常量成员在编译时定义,不能在运行时更改。常量被声明为一个字段,使用 const 关键字,并且必须在声明时进行初始化。

public class MyClass
{
    public const double PI1 = 3.14159;
}

A readonly 成员就像一个常量,它代表一个不变的值。不同的是,一个 readonly 成员可以在运行时在构造函数中初始化,也可以在声明时初始化。

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

常量

  • 它们不能被声明为 static (它们是隐式静态的)
  • 常量的值在编译时计算
  • 常量仅在声明时初始化

只读

  • 它们可以是实例级的或静态的
  • 该值在运行时评估
  • readonly 可以在声明中或通过构造函数中的代码进行初始化

const 是编译时常量,而 readonly 允许在运行时计算值并在构造函数或字段初始值设定项中设置。因此,“const”始终是常量,但“readonly”一旦被分配就是只读的。

埃里克·利珀特 C# 团队的 提供了有关不同类型不变性的更多信息

这是另一个链接 演示 const 为何不是版本安全的,或者与引用类型相关。

概括:

  • const 属性的值是在编译时设置的,不能在运行时更改
  • Const 不能标记为静态 - 关键字表示它们是静态的,这与只读字段可以标记为静态不同。
  • Const 不能是除值(原始)类型之外的任何内容
  • readonly 关键字将该字段标记为不可更改。但是,可以在类的构造函数内更改该属性
  • readonly 关键字也可以与 static 结合使用,使其与 const 的行为方式相同(至少表面上如此)。当您查看两者之间的 IL 时,会发现明显的差异
  • const 字段在 IL 中被标记为“literal”,而 readonly 被标记为“initonly”

只读 :可以在运行时通过 Ctor 更改值。但不是通过成员函数

持续的 :默认静态。值不能从任何地方更改(Ctor、函数、运行时等)

还有一个问题:只读值可以通过反射被“狡猾的”代码更改。

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

我可以使用反射更改 C# 中的私有只读继承字段吗?

我相信一个 const 所有对象的值都是相同的(并且必须用文字表达式初始化),而 readonly 每个实例可以不同......

我们办公室的一位团队成员就何时使用 const、static 和 readonly 提供了以下指导:

  • 使用 常量 当您有某种类型的变量时,您可以在运行时知道(字符串文字、int、double、枚举...)您希望类的所有实例或使用者都可以访问值不应更改的位置。
  • 使用 静止的 当您拥有数据并希望类的所有实例或使用者都能够访问值可以更改的位置时。
  • 使用 静态只读 当您有一个在运行时无法知道的类型的变量(对象)时,您希望类的所有实例或使用者都可以访问该值不应更改的位置。
  • 使用 只读 当您有实例级变量时,您会在创建对象时知道该变量不应更改。

最后一点:const 字段是静态的,但反之则不然。

它们都是常量,但 const 在编译时也可用。这意味着差异的一方面是您可以使用 const 变量作为属性构造函数的输入,但不能使用只读变量。

例子:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

标记为 const 的变量与强类型 #define 宏没什么区别,在编译时 const 变量引用将被替换为内联文字值。因此,只有某些内置原始值类型可以以这种方式使用。标记为只读的变量可以在运行时在构造函数中设置,并且它们的只读性也在运行时强制执行。与此相关的性能成本较小,但这意味着您可以对任何类型(甚至引用类型)使用只读。

此外,const 变量本质上是静态的,而只读变量如果需要的话可以是特定于实例的。

其他 陷阱.

由于 const 实际上只适用于基本数据类型,因此如果您想使用类,您可能会感到“被迫”使用 ReadOnly。不过,要小心陷阱!ReadOnly 意味着你不能用另一个对象替换该对象(你不能让它引用另一个对象)。但是任何引用该对象的进程都可以自由修改这些值 里面 物体!

因此,不要误认为 ReadOnly 意味着用户无法更改内容。C# 中没有简单的语法来防止类的实例化其内部值发生更改(据我所知)。

C#.Net 中 const 字段和 readonly 字段之间存在显着差异

const 默认是静态的,需要用常量值初始化,以后不能修改。构造函数中也不允许更改值。它不能与所有数据类型一起使用。对于前日期时间。它不能与 DateTime 数据类型一起使用。

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public readonly string Name = string.Empty; //No error, legal

readonly 可以声明为静态,但不是必需的。声明时无需初始化。可以使用构造函数分配或更改其值。因此,它在用作实例类成员时具有优势。两个不同的实例化可能具有不同的只读字段值。对于前 -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

然后只读字段可以用即时特定值初始化,如下所示:

A objOne = new A(5);
A objTwo = new A(10);

这里,实例 objOne 的 readonly 字段值为 5,而 objTwo 的值为 10。使用 const 是不可能的。

常量将作为文字值编译到使用者中,而静态字符串将用作对定义值的引用。

作为练习,尝试创建一个外部库并在控制台应用程序中使用它,然后更改库中的值并重新编译它(无需重新编译消费者程序),将 DLL 放入目录中并手动运行 EXE,您应该会发现常量字符串不会改变。

持续的

我们需要在定义 const 字段时为其提供值。然后,编译器将常量的值保存在程序集的元数据中。这意味着只能为基本类型(如 boolean、char、byte 等)定义常量。常量始终被视为静态成员,而不是实例成员。

只读

只读字段只能在运行时解析。这意味着我们可以使用声明字段的类型的构造函数来定义值。编译器会验证只读字段不会被构造函数以外的任何方法写入。

关于两者的更多信息 本文对此进行了解释

常量

  1. const 关键字可以应用于字段或局部变量
  2. 我们必须在声明时分配 const 字段
  3. 未分配内存因为 const 值在编译后嵌入到 IL 代码本身中。这就像查找所有出现的 const 变量并替换为它的值。因此编译后的 IL 代码将用硬编码值代替 const 变量
  4. C# 中的 Const 默认是静态的。
  5. 该值对于所有对象都是恒定的
  6. 存在 dll 版本控制问题 - 这意味着每当我们更改公共 const 变量或属性(事实上,理论上不应更改),任何使用此变量的其他 dll 或程序集都必须重新构建
  7. 只有 C# 内置类型可以声明为常量
  8. Const 字段不能作为 ref 或 out 参数传递

只读

  1. readonly 关键字仅适用于字段而不是局部变量
  2. 我们可以在声明时或构造函数中分配只读字段,而不是在任何其他方法中。
  3. 为只读字段分配动态内存,我们可以在运行时获取值。
  4. 只读属于仅通过类实例访问而创建的对象。为了使其成为类成员,我们需要在 readonly 之前添加 static 关键字。
  5. 该值可能会有所不同,具体取决于所使用的构造函数(因为它属于该类的对象)
  6. 如果将非基本类型(引用类型)声明为只读,则仅引用是不可变的,而不是它包含的对象。
  7. 由于该值是在运行时获取的,因此只读字段/属性不存在 dll 版本控制问题。
  8. 我们可以在构造函数上下文中将只读字段作为 ref 或 out 参数传递。

原则上;您可以在运行时将静态只读字段的值分配给非常量值,而必须为 const 分配常量值。

A const 必须 硬编码的, , 然而 readonly在构造函数中设置 班级的。

const 和 readonly 很相似,但并不完全相同。const 字段是编译时常量,这意味着可以在编译时计算该值。只读字段支持在类型构造期间必须运行某些代码的其他场景。构建后,只读字段无法更改。

例如,const 成员可用于定义如下成员:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

因为像 3.14 和 0 这样的值是编译时常量。但是,请考虑您定义类型并希望提供它的一些预制实例的情况。例如,您可能想要定义一个 Color 类并为黑色、白色等常见颜色提供“常量”。不可能对 const 成员执行此操作,因为右侧不是编译时常量。可以使用常规静态成员来做到这一点:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

但是,没有什么可以阻止彩色客户对其进行破坏,也许可以通过交换黑白值来实现。不用说,这会让 Color 类的其他客户感到惊愕。“只读”功能解决了这种情况。通过简单地在声明中引入 readonly 关键字,我们保留了灵活的初始化,同时防止客户端代码乱七八糟。

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

有趣的是,const 成员始终是静态的,而只读成员可以是静态的,也可以不是静态的,就像常规字段一样。

可以使用单个关键字来实现这两个目的,但这会导致版本控制问题或性能问题。假设我们为此使用了一个关键字(const),并且开发人员写道:

public class A
{
    public static const C = 0;
}

另一位开发人员编写了依赖于 A 的代码:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

现在,生成的代码可以依赖 A.C 是编译时常量这一事实吗?即,可以将 A.C 的使用简单地替换为值 0 吗?如果你对此说“是”,那么这意味着 A 的开发者不能改变 A.C 的初始化方式——这在未经许可的情况下束缚了 A 开发者的手脚。如果您对这个问题说“不”,那么就会错过一个重要的优化。也许 A 的作者确信 A.C 永远为零。const 和 readonly 的使用允许 A 的开发人员指定意图。这可以实现更好的版本控制行为和更好的性能。

ReadOnly :该值只会从类的构造函数中初始化一次。
常量:可以在任何函数中初始化,但只能初始化一次

不同之处在于静态只读字段的值是在运行时设置的,因此对于程序的不同执行它可以具有不同的值。然而,const 字段的值被设置为编译时常量。

记住:对于引用类型,在两种情况下(静态和实例),readonly 修饰符仅阻止您向字段分配新引用。具体来说,它不会使引用所指向的对象变得不可变。

有关详细信息,请参阅有关此主题的 C# 常见问题:http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

常量变量在编译时声明和初始化。此后该值无法更改。只读变量只能从类的静态构造函数中初始化。仅当我们想在运行时赋值时才使用只读。

在上面人们所说的基础上补充一件事。如果您有一个包含只读值的程序集(例如只读 MaxFooCount = 4;),您可以通过发布具有不同值的该程序集的新版本来更改调用程序集看到的值(例如只读 MaxFooCount = 5;)

但是使用 const 时,在编译调用者时,它将被折叠到调用者的代码中。

如果您已达到此 C# 熟练程度,则可以阅读 Bill Wagner 的书《Effective C#》:改进C#的50种特定方法,该方法详细回答了这个问题(以及其他49件事)。

主要区别在于 Const 相当于 C 语言中的#DEFINE。该数字实际上被预编译器替换。Readonly 实际上被视为变量。

当项目 A 依赖于项目 B 的公共常量时,这种区别尤其重要。假设公共常数发生变化。现在,您选择的 const/readonly 将影响项目 A 的行为:

成本:项目 A 不会捕获新值(当然,除非使用新的 const 重新编译),因为它是使用替换的常量进行编译的。

只读:项目 A 总是会向项目 B 询问其变量值,因此它将获取 B 中公共常量的新值。

老实说,我建议您对几乎所有内容都使用只读,除了真正的通用常量(例如Pi,英寸到厘米)。对于任何可能改变的事情,我建议使用只读。

希望这会有所帮助,艾伦。

简单来说,Const 是编译时,readonly 是运行时。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top