C#中 const 和 readonly 有什么区别?

C#中constreadonly什么区别?

您什么时候可以使用另一个?

答案

除了明显的区别

  • 必须在定义const时声明值,VS readonly值可以动态计算,但需要在构造函数退出之前分配。在冻结之后。
  • 'const's 是隐式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值的情况下,就像是一个查找替换,值 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;

但是,如果您有一个可能会更改的常量(例如,精度),或者有疑问,请使用readonly

public readonly float PI = 3.14;

更新:Aku 需要得到提及,因为他首先指出了这一点。另外,我需要在我学到的知识上加点代码。 有效的 C#-Bill Wagner

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

常数

  • 常量默认为静态
  • 它们在编译时必须有一个值(例如,可以有 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 必须在声明时初始化,只读可以在构造函数上初始化(因此,根据所使用的构造函数的不同,其值也不同)。

编辑:请参阅上面的 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关键字将const声明为字段,并且必须在声明const对其进行初始化。

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

readonly成员就像常量一样,它表示不变的值。区别在于, readonly成员可以在运行时在构造函数中初始化,并且可以在声明它们时进行初始化。

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

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

只读

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

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

C#小组的Eric Lippert拥有有关不同类型不变性的更多信息

这是另一个链接,说明 const 如何不是版本安全的,或者与引用类型无关。

总结

  • const 属性的值是在编译时设置的,在运行时不能更改
  • 常量不能被标记为静态 - 关键字表示它们是静态的,与只读字段不同。
  • 常量除值(原始)类型外不能为其他任何东西
  • readonly 关键字将字段标记为不可更改。但是,可以在类的构造函数中更改属性
  • readonly only 关键字也可以与 static 组合使用,以使其与 const(至少在表面上)具有相同的作用。当您查看两者之间的 IL 时,有明显的区别
  • const 字段在 IL 中被标记为 “文字”,而 readonly 是 “initonly”