const和readonly有什么区别?

时间:2008-09-11 08:02:19

标签: c# .net const constants readonly

const readonly 之间的区别是什么?您是否使用其中一个?

34 个答案:

答案 0 :(得分:1133)

除了

的明显差异
  • 必须声明const VS readonly值定义时的值,可以动态计算,但需要在构造函数退出之前分配..之后它被冻结。< / LI>
  • '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;
  }
}

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

  • const值的情况下,它就像一个find-replace,值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;

但如果你有一个可能改变的常数(例如w.r.t. precision)..或者有疑问,请使用readonly

public readonly float PI = 3.14;

更新:Aku需要提一下因为他首先指出了这一点。此外,我需要插入我学到的地方.. Effective C# - Bill Wagner

答案 1 :(得分:257)

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

答案 2 :(得分:142)

常量

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

只读实例字段

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

静态只读字段

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

答案 3 :(得分:54)

只是要添加,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
  }
}

答案 4 :(得分:37)

This explains it。总结:const必须在声明时初始化,readonly可以在构造函数上初始化(因此根据使用的构造函数有不同的值)。

编辑:请参阅Gishu上面提到的微妙差异

答案 5 :(得分:29)

const:无法在任何地方更改。

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

答案 6 :(得分:24)

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

答案 7 :(得分:22)

常量成员在编译时定义,不能在运行时更改。常量使用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;
     }
}

<强>常量

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

<强>只读

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

答案 8 :(得分:20)

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

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

答案 9 :(得分:15)

Here's another link演示了const不是版本安全的,或者与引用类型相关。

<强>摘要

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

答案 10 :(得分:9)

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

常量: 通过defult静态。价值不能从任何地方改变(Ctor,Function,runtime等no-where)

答案 11 :(得分:8)

还有另一个问题:readonly值可以通过反射来改变“狡猾”代码。

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

Can I change a private readonly inherited field in C# using reflection?

答案 12 :(得分:6)

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

答案 13 :(得分: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; }
  }
}

答案 14 :(得分:5)

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

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

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

答案 15 :(得分:4)

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

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

答案 16 :(得分:3)

另一个陷阱

由于const实际上只适用于基本数据类型,如果你想使用类,你可能会感到“被迫”使用ReadOnly。但是,要小心陷阱! ReadOnly意味着您不能用另一个对象替换该对象(您不能使它引用另一个对象)。但任何引用该对象的进程都可以自由修改 对象中的值!

因此,不要混淆认为ReadOnly意味着用户无法改变事物。 C#中没有简单的语法来防止类的实例化使其内部值发生变化(据我所知)。

答案 17 :(得分:3)

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

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

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

然后,readonly字段可以使用即时特定值进行初始化,如下所示:

A objOne = new A(5);
A objTwo = new A(10);

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

答案 18 :(得分:2)

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

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

答案 19 :(得分:2)

常量:

声明为const(读取:常量)的变量必须在声明时分配一个值,此值以后不得更改。

  

公共常量字符串ConnectionString =“ YourConnectionString”;

const变量中的值就是所谓的“编译时”值。

静态:

静态成员(变量,方法等)属于对象的类型,而不是该类型的实例。因此,如果我们声明:

    public class MyClass  {
       public static string MyMethod() { ... } 
}

我们必须像这样调用此方法:

  

var result = MyClass.MyMethod();

只读:

只读字段是指对该字段的赋值只能作为类声明的一部分或在构造函数中发生的字段。

public class TestClass
{
    public readonly string ConnectionString = "TestConnection";

    public TestClass()
    {
        ConnectionString = "DifferentConnection";
    }

    public void TestMethod ()
    {
        ConnectionString = "NewConnection";//Will not compile
    }
}

这意味着对于同一类中的不同构造函数,只读变量可以具有不同的值。

答案 20 :(得分:2)

CONST

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

ReadOnly

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

答案 21 :(得分:2)

<强>恒

我们需要在定义时为const字段提供值。然后,编译器将常量的值保存在程序集的元数据中。这意味着只能为boolean,char,byte等基本类型定义常量。常量始终被视为静态成员,而不是实例成员。

<强>只读

只能在运行时解析只读字段。这意味着我们可以使用声明字段的类型的构造函数为值定义值。验证由编译器完成,只读字段不是由构造函数以外的任何方法写入的。

有关explained here in this article

的详情

答案 22 :(得分:1)

不同之处在于静态只读字段的值是在运行时设置的,因此对于程序的不同执行,它可以具有不同的值。但是,const字段的值设置为编译时常量。

记住: 对于引用类型,在两种情况下(静态和实例),只读修饰符仅阻止您为字段分配新引用。它特别不会使引用所指向的对象成为不可变的。

有关详细信息,请参阅有关此主题的C#常见问题解答: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

答案 23 :(得分:1)

  • 何时使用constreadonly

    • const

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

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

答案 24 :(得分:1)

在编译时声明并初始化常量变量。病房后无法更改该值。只读变量将仅从类的静态构造函数初始化。只有在我们想要在运行时分配值时才使用只读。

答案 25 :(得分:1)

ReadOnly:该值仅从类的构造函数初始化一次 const:可以在任何函数中初始化,但只能初始化

答案 26 :(得分:1)

Const和readonly是相似的,但它们并不完全相同。 const字段是编译时常量,这意味着该值可以在编译时计算。只读字段允许在构造类型期间必须运行某些代码的其他方案。构建完成后,无法更改只读字段。

例如,const成员可用于定义以下成员:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

因为像3.14和0这样的值是编译时常量。但是,请考虑您定义类型并希望提供一些预制实例的情况。例如,您可能想要定义一个Color类并提供&#34;常量&#34;对于常见的颜色,如黑色,白色等。使用const成员执行此操作是不可能的,因为右侧不是编译时常量。可以使用常规静态成员执行此操作:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

然而,没有任何东西可以阻止Color的客户端使用它,也许通过交换黑白值。不用说,这会导致Color类的其他客户端惊慌失措。 &#34; readonly&#34;功能解决了这种情况。通过在声明中简单地引入readonly关键字,我们保留了灵活的初始化,同时防止客户端代码混乱。

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

值得注意的是,const成员总是静态的,而readonly成员可以是静态的,也可以不是静态的,就像常规字段一样。

可以使用单个关键字来实现这两个目的,但这会导致版本控制问题或性能问题。假设我们为此(const)使用了一个关键字,开发人员写道:

public class A
{
    public static const C = 0;
}

和另一位开发人员编写的代码依赖于A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

现在,生成的代码能否依赖于A.C是编译时常量的事实?即,A.C的使用可以简单地用值0代替吗?如果你说&#34;是&#34;对此,这意味着A的开发人员无法改变A.C初始化的方式 - 这在未经许可的情况下将A的开发人员联系起来。如果你说&#34; no&#34;对于这个问题,然后错过了一个重要的优化。也许A的作者肯定A.C永远是零。 const和readonly的使用允许A的开发者指定意图。这样可以获得更好的版本控制行为以及更好的性能。

答案 27 :(得分:1)

const必须硬编码,其中readonly可以在类的构造函数中设置。

答案 28 :(得分:1)

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

答案 29 :(得分:0)

添加人们上面所说的一件事。如果你有一个包含readonly值的程序集(例如readonly MaxFooCount = 4;),你可以通过运送具有不同值的那个程序集的新版本来更改调用程序集看到的值(例如readonly MaxFooCount = 5;)

但是使用const,它会在编译调用者时被折叠到调用者的代码中。

如果你已经达到了这个C#熟练程度,那么你已经准备好了Bill Wagner的书,有效的C#:50改善你的C#的具体方法 其中详细回答了这个问题,(以及其他49个问题)。

答案 30 :(得分:0)

关键区别在于Const是#DEFINE的C等价物。字面上的数字取代了a-la预编译器。 Readonly实际上被视为变量。

当项目A取决于项目B的公共常量时,这种区别尤其重要。假设公共常量发生变化。现在,您选择const / readonly将影响项目A的行为:

Const:项目A没有捕获新值(当然,除非使用新的const重新编译),因为它是使用在其中定义的常量编译的。

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

老实说,除了真正的通用常量(例如Pi,Inches_To_Centimeters)之外,我建议你几乎使用readonly。对于任何可能发生变化的事情,我说只使用readonly。

希望这有帮助, 艾伦。

答案 31 :(得分:0)

简单来说,Const是编译时,而readonly是运行时。

答案 32 :(得分:0)

常量:应用程序生存期内的绝对常数。

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

答案 33 :(得分:0)

只读字段的值可以更改。但是,const 字段的值不能更改。

在只读字段中,我们可以在声明时或在该类的构造函数中赋值。如果是常量,我们只能在声明时赋值。

只读可以与静态修饰符一起使用,但常量不能与静态一起使用。