在C#中常量和只读之间有什么区别?

你什么时候会用一个代替另一个?


当前回答

除了

必须在常量VS只读值的定义时声明该值可以动态计算,但需要在构造函数退出之前赋值。之后,它被冷冻。常量是隐式静态的。您使用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并在代码中使用这些值。编译时:

对于常量值,它就像查找替换。值2被“烘焙”到AssemblyB的IL中。这意味着如果明天我将I_CONST_value更新为20,AssemblyB仍将有2,直到我重新编译它。在只读值的情况下,它类似于对内存位置的引用。该值不会烘焙到AssemblyB的IL中。这意味着如果更新了内存位置,AssemblyB将在不重新编译的情况下获得新值。因此,如果I_RO_VALUE更新为30,则只需要构建AssemblyA,而不需要重新编译所有客户端。

因此,如果你确信常数的值不会改变,那么使用常量。

public const int CM_IN_A_METER = 100;

但是,如果您有一个可能会改变的常数(例如w.r.t.精度),或者当有疑问时,请使用只读。

public readonly float PI = 3.14;

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

其他回答

常量

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

只读

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

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

但如果使用常量,则在编译调用者时,它将被折叠到调用者的代码中。

如果你已经达到了C#的熟练程度,你就可以阅读比尔·瓦格纳的书《有效的C#:提高你的C语言的50种具体方法》了#它详细回答了这个问题(以及其他49个问题)。

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

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

Const:应用程序生命周期内的绝对常量值。

只读:可以在运行时更改。

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

常量:默认情况下为静态。值不能从任何位置更改(Ctor、Function、runtime等no where)