const和readonly有什么区别?

时间:2020-03-05 18:51:17  来源:igfitidea点击:

constreadonly有什么区别,我们是否在一个之上使用另一个?

解决方案

回答

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

回答

这解释了它。简介:const必须在声明时初始化,只读可以在构造函数上初始化(因此,根据所使用的构造函数的不同,其值也不同)。

编辑:参见上面的Gishu的陷阱以获得微妙的区别

回答

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

团队的埃里克·利珀特(Eric Lippert)拥有有关不同类型不变性的更多信息

回答

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

回答

除了明显的区别

  • 可以在定义const时声明值,而VS的readonly值可以动态计算,但是需要在构造函数退出之前分配。在冻结之后。
  • const是隐式的"静态"。我们可以使用" 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个。
  • 如果是"只读"值,则类似于对存储位置的"引用"。该值未烘焙到" AssemblyB"的IL中。这意味着如果内存位置被更新,则" AssemblyB"将获得新值而无需重新编译。因此,如果将" I_RO_VALUE"更新为30,则只需构建" AssemblyA"。不需要重新编译所有客户端。

因此,如果我们确信常量的值不会改变,请使用const。

public const int CM_IN_A_METER = 100;

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

public readonly float PI = 3.14;

更新:Aku需要提及,因为他首先指出了这一点。另外,我需要在我学到的知识上加点文字。.有效的CBill Wagner

回答

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

同样,const变量本质上是静态的,而如果需要的话,只读变量可以是实例特定的。

回答

只需添加一下,对于引用类型的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
  }
}

回答

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

但是使用const时,将在编译调用方时将其折叠到调用方的代码中。

如果我们已经达到此水平,则可以阅读Bill Wagner的书《有效的C#:提高C语言的50种特定方法》。
其中详细回答了这个问题(以及其他49件事)。

回答

关键区别在于Const是#DEFINE的C等效项。该数字从字面上被替换为a-la预编译器。只读实际上被视为变量。

当我们拥有项目A依赖于项目B中的公共常量时,这种区别尤其重要。假设公共常量发生了变化。现在,我们选择的const / readonly将影响项目A上的行为:

const:项目A不会捕获新值(当然,除非使用新的const重新编译),因为它是使用替换了的常量进行编译的。

ReadOnly:项目A总是向项目B询问变量值,因此它将在B中获取公共常量的新值。

老实说,我建议我们对除真正的通用常量(例如Pi,Inches_To_Centimeters)之外的几乎所有内容都使用只读。对于可能会更改的任何内容,我说使用只读。

希望这可以帮助,
艾伦

回答

它们都是常量,但是在编译时也可以使用const。这意味着区别的一方面是可以将const变量用作属性构造函数的输入,但不能使用readonly变量。

例子:

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; }
  }
}

回答

回答

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

  • 当我们拥有一个在运行时可以知道的类型的变量(字符串文字,int,double,enums ...)时,请使用const,希望类的所有实例或者使用者都可以访问该值不应更改的位置。
  • 当我们拥有希望类的所有实例或者使用者可以访问值可以更改的位置的数据时,请使用static。
  • 当我们拥有一个在运行时(对象)不知道的类型的变量,并且希望类的所有实例或者使用者都可以访问该值不应更改的位置时,请使用静态只读。
  • 当我们有一个实例级别的变量,该变量在创建对象时会知道,该变量不应更改,请使用只读。

最后一点:const字段是静态的,但反之则不正确。

回答

有一个只读的小陷阱。可以在构造函数中多次设置只读字段。即使在两个不同的链式构造函数中设置了值,也仍然允许。

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
    }
}

回答

常数

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

只读实例字段

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

静态只读字段

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

回答

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

概括:

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

回答

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

作为练习,尝试创建一个外部库并在控制台应用程序中使用它,然后更改该库中的值并重新编译(无需重新编译使用者程序),将DLL放到目录中并手动运行EXE,我们应该找到常量字符串不变。

回答

原则上;我们可以在运行时将值分配给静态只读字段,并将其分配给非常量值,而必须为const分配常量。

回答

还有一个陷阱:只读值可以通过反射的"欺骗"代码来更改。

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

我可以在Cusing Reflection中更改私有只读继承字段吗?