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

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


当前回答

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

其他回答

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

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

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

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

只读成员就像一个常量,因为它代表一个不变的值。不同之处在于,只读成员可以在运行时在构造函数中初始化,也可以在声明时初始化。

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

常量

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

只读的

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

除了

必须在常量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#-比尔·瓦格纳

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

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

我们办公室的一名团队成员就何时使用常量、静态和只读提供了以下指导:

当您有一个在运行时可以知道的类型的变量(string literal、int、double、enums…),您希望类的所有实例或使用者都可以访问值不应更改的位置时,请使用const。如果您希望类的所有实例或使用者都可以访问值可以更改的数据,请使用静态。当您有一个在运行时无法知道的类型的变量(对象),您希望类的所有实例或使用者都可以访问值不应更改的位置时,请使用静态只读。当您有一个实例级变量时,您将在创建对象时知道该变量不应更改,请使用readonly。

最后一个注意事项:常量字段是静态的,但反之则不是真的。