题 const和readonly有什么区别?


有什么区别 const 和 readonly 你用另一个吗?


993
2017-09-11 08:02


起源


该值将仅从类的构造函数初始化一次。 - donstack
两个关键词做同样的事情。如果我们宣布成员 常量 / 只读 它无法在整个计划中进行更改。有一些区别 常量 应该在程序中使用之前进行初始化。和 常量 是隐式静态的,因此可以使用类名调用它。 Class_Name.ConstantName - Balaji
我不得不看几个答案找到这个链接,但这是一个很好的。 Eric Lippert在C#中对不变性的看法 - Frank Bryce
我喜欢你的名字 :-) - Alexander Derck
“readonly关键字与const关键字不同。一个const字段只能在字段的声明中初始化。只读字段可以在声明或构造函数中初始化。因此,只读字段可以具有不同的值,具体取决于使用的构造函数。另外,虽然const字段是编译时常量,但readonly字段可用于运行时常量,如下例所示......“ msdn.microsoft.com/en-us/library/acdd6hb7.aspx - cp.engr


答案:


除了明显的差异

  • 必须在a的定义时声明值 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 值,它就像一个find-replace,值2被'烘焙'了 AssemblyB我的IL。这意味着如果明天我会更新 I_CONST_VALUE 将来到20岁。 AssemblyB 直到我重新编译它仍然会有2
  • 在这种情况下 readonly 价值,就像一个 ref 到内存位置。该值未被烘焙 AssemblyB我的IL。这意味着如果更新内存位置, AssemblyB 获取新值而无需重新编译。因此,如果 I_RO_VALUE 更新到30,你只需要构建 AssemblyA。所有客户端都不需要重新编译。

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

public const int CM_IN_A_METER = 100;

但是如果你有一个可能改变的常数(例如w.r.t. precision)..或者有疑问,请使用a readonly

public readonly float PI = 3.14;

更新:Aku需要得到一个提及因为他首先指出了这一点。另外我需要插上我学到的东西.. 有效的C# - 比尔瓦格纳


980
2017-09-11 08:24



该 static 点似乎是最重要和最有用的一点 - consts are implicitly static - Lijo
关于参考值的部分是最重要的部分。可以优化Const值。 - CodingBarfield
readonly 变量可以在构造函数之外更改(反射)。只有编译器试图阻止你修改构造函数之外的var。 - Bitterblue
@小我 readonly 一旦构造函数完成,即使通过反射,也不允许更改变量。运行时碰巧没有强制执行此操作。运行时也不会强制您不要更改 string.Empty 至 "Hello, world!",但我仍然不会声称这样做 string.Empty 可修改的,或者代码不应该假设 string.Empty 将始终是一个零长度的字符串。 - hvd
blogs.msmvps.com/jonskeet/2014/07/16/... 是一个有趣的只读读取的开销成本 - CAD bloke


有一个充满争议的问题!如果从另一个程序集引用常量,则其值将被编译到调用程序集中。这样,当您更新引用的程序集中的常量时,它将不会在调用程序集中更改!


238
2017-09-11 08:15



在反编译(Reflector,ILSpy,..)时,任何一个都会引用一个永恒的永恒,无论是相同的程序集还是其他程序集,所以你根本不能分析编译代码中常量的用法。 - springy76


常量

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

只读实例字段

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

静态只读字段

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

125
2017-12-02 11:50





只是要添加,ReadOnly用于引用类型只使引用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
  }
}

49
2017-09-11 10:37



还有其他参考类型吗? string 你可以用作常数吗? - springy76
你可以有 const 使用除string之外的引用类型,但常量只能具有该值 null。 - Mike Rosoft


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

编辑:看到Gishu的上面的细微差别


37
2017-09-11 08:04





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

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


25
2018-05-21 13:21





有一个小的陷阱与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
    }
}

20
2017-10-19 22:14



很高兴知道!!好点。 - Levit


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

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

一个 readonly 成员就像一个常数,因为它代表了一种不变的价值。区别在于a readonly 成员可以在运行时,构造函数中初始化,也可以在声明它们时进行初始化。

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

常量

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

只读

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

20
2017-09-17 11:48



他们不能是静止的,他们是静止的。如果你的意思,你应该说清楚 一个人不能宣布 static const int i = 0; - nawfal
你能解释一下原因吗? const 内部方法无法声明声明? - Minh Tran


const是一个编译时常量,而readonly允许在运行时计算一个值,并在构造函数或字段初始化程序中设置。因此,'const'始终是常量,但'readonly'只有在分配后才是只读的。

Eric Lippert C#团队提供了有关不同类型的不变性的更多信息


19
2017-09-11 08:07