const和readonly有什么区别?

Rea*_*nly 1269 .net c# const constants readonly

是什么区别const,并readonly和你使用一个比其他?

Gis*_*shu 1214

除了明显的差异

  • 必须声明constVS 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

AssemblyB引用AssemblyA并在代码中使用这些值.编译时,

  • const值的情况下,它就像一个find-replace,值2被'烘焙'到AssemblyB'IL'.这意味着如果明天我将来会更新I_CONST_VALUE到20.AssemblyB直到我重新编译它仍然会有2.
  • readonly值的情况下,它就像ref一个内存位置.该值未被烘焙到AssemblyBIL中.这意味着如果更新内存位置,则AssemblyB获取新值而不重新编译.所以如果I_RO_VALUE更新到30,你只需要构建AssemblyA.所有客户端都不需要重新编译.

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

public const int CM_IN_A_METER = 100;
Run Code Online (Sandbox Code Playgroud)

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

public readonly float PI = 3.14;
Run Code Online (Sandbox Code Playgroud)

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

  • `static`点似乎是最重要和最有用的点 - "consts是隐式静态的" (71认同)
  • 关于参考值的部分是最重要的部分.可以优化Const值. (27认同)
  • `readonly`变量可以在构造函数(反射)之外更改.只有编译器试图阻止你修改构造函数之外的var. (20认同)
  • @ mini-me`readonly`变量一旦构造函数完成就不允许更改,即使是通过反射也是如此.运行时碰巧没有强制执行此操作.运行时也没有强制你不要将`string.Empty`更改为`"Hello,world!"`,但我仍然不会声称这会使`string.Empty`可修改,或者代码不应该'假设`string.Empty`将始终是零长度字符串. (10认同)
  • http://blogs.msmvps.com/jonskeet/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/是一个有趣的只读读取费用 (6认同)
  • @mini-me 这与我所说的并不矛盾。它们不允许被更改,CIL 规范明确禁止它,但运行时不强制它,并且 CIL 规范不要求(但允许)运行时强制它。修改“readonly”字段的代码是一个活跃的定时炸弹,当运行时确实开始强制执行时,它就会爆炸。 (2认同)
  • 这与方法的默认参数的情况相同。与常量一样,它们的默认值嵌入在客户端的调用中,如果您更改方法定义中默认参数的值并仅重新编译该程序集,客户端程序集仍将具有旧值。 (2认同)

aku*_*aku 266

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

  • 在反编译(Reflector,ILSpy,..)中,任何一个都可以引用常量永远的永恒,无论是相同的程序集还是其他程序集,因此您根本无法分析编译代码中常量的用法. (7认同)

spl*_*tne 151

常量

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

只读实例字段

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

静态只读字段

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


小智 55

只是要添加,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
  }
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*vic 39

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

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


小智 31

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

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


Mik*_*Two 26

有一个小的陷阱与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
    }
}
Run Code Online (Sandbox Code Playgroud)


Suj*_*jit 25

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

public class MyClass
{
    public const double PI1 = 3.14159;
}
Run Code Online (Sandbox Code Playgroud)

readonly构件是一样的,因为它代表了一个不变的值的常数.不同之处在于readonly成员可以在运行时,构造函数中初始化,也可以在声明它们时进行初始化.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}
Run Code Online (Sandbox Code Playgroud)

常量

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

只读

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

  • *它们不能是静态的*,它们是静态的.你应该说清楚,如果你的意思是*一个人不能声明`static const int i = 0;`* (6认同)

Whe*_*lie 20

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

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


Chr*_*s S 15

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

摘要:

  • const属性的值在编译时设置,不能在运行时更改
  • Const不能被标记为静态 - 关键字表示它们是静态的,不像readonly字段那样.
  • 除了值(原始)类型之外,Const不能是任何东西
  • readonly关键字将该字段标记为不可更改.但是,可以在类的构造函数内更改属性
  • readonly only关键字也可以与static结合使其以与const(表面上至少)相同的方式运行.当你看两者之间的IL时,有一个显着的差异
  • const字段在IL中标记为"literal",而readonly是"initonly"


Yea*_*iam 10

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

常数:通过defult静态.价值无法从任何地方改变(Ctor,Function,runtime等no-where)

  • 感谢您没有让我只为这两个外卖而阅读 4 段... (2认同)

Gre*_*reg 8

还有另一个问题:readonly值可以通过反射的"狡猾"代码来改变.

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

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


Dar*_*mas 6

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


Muh*_* VP 6

常数

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

只读

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


Rya*_*ndy 6

  • 何时使用constreadonly

    • const

      • 编译时常量:绝对常量,值在声明期间设置,在 IL 代码本身中
    • readonly

      • 运行时常量:可以通过配置文件 ie 在构造函数/init 中设置App.config,但一旦初始化就无法更改


Wed*_*dge 5

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

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


Hal*_*rim 5

它们都是常量,但在编译时也可以使用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; }
  }
}
Run Code Online (Sandbox Code Playgroud)


Sco*_*nce 5

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

  • 当你有一个你可以在运行时知道的类型的变量(字符串文字,整数,双数,枚举......)时,你希望使用const,你希望类的所有实例或消费者都能访问值不应该改变的地方.
  • 当您拥有希望类的所有实例或使用者可以访问值可以更改的位置的数据时,请使用static.
  • 当您拥有一个在运行时无法知道的类型变量(对象)时,请使用静态只读,您希望类的所有实例或使用者都可以访问值不应更改的位置.
  • 当您拥有一个实例级变量时,只要使用readonly,您将在创建对象时知道该变量不应该更改.

最后要注意的是:const字段是静态的,但反之则不然.


Chi*_*rag 5

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
Run Code Online (Sandbox Code Playgroud)

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

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

A objOne = new A(5);
A objTwo = new A(10);
Run Code Online (Sandbox Code Playgroud)

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