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

1692

constreadonly 在 C# 中有什么区别?

在什么情况下会使用其中一个而不是另一个?


4
我需要查看好几个答案才找到这个链接,但它很不错。Eric Lippert在C#中关于不可变性的看法。 - Frank Bryce
5
@donstack,根据C# 参考文档的说明,只读字段可以在字段声明和构造函数中被赋值和重新赋值多次。 - Marques
这里是const和readonly的详细解释: https://youtu.be/jA30qZNGNoM - Parveen
30个回答

20

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

常量: 默认为静态。无论是在 Ctor、函数还是运行时,值都无法从任何地方更改。


2
谢谢您没有让我读四段文字才能得到这两个要点... - Don Cheadle

14

12
我认为const值对于所有的对象都是相同的(必须使用字面表达式进行初始化),而readonly则可以针对每个实例不同...

9
他们都是常量,但 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; }
  }
}

9
  • 何时使用constreadonly

    • const

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

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

9
我们办公室的一位团队成员提供了以下关于何时使用const、static和readonly的指导:
  • 当您有一个可以在运行时知道类型的变量(字符串文字、int、double、枚举等),并且您希望所有类实例或使用者都能访问该值但该值不应更改时,请使用const
  • 当您有数据需要所有类实例或使用者都能访问但其值可以更改时,请使用static
  • 当您有无法在运行时知道类型的变量(对象),并且您希望所有类实例或使用者都能访问该值但该值不应更改时,请使用static readonly
  • 当您有一个实例级变量,在对象创建时会知道该变量,而且该变量不应更改时,请使用readonly
最后请注意:常量字段是静态的,但反之则不成立。

1
我认为你的意思是“相反”。反过来的话应该是“一个非常量字段不是静态的”,这可能是真的,也可能不是。而“一个静态字段总是常量”这个相反命题是不正确的。 - Michael Blackburn

8

CONST

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

ReadOnly

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

6
标记为“const”的变量不过是具有强类型化的#define宏,在编译时,const变量引用会被替换为内联文字值。因此,只有特定的内置基元类型可以用这种方式进行操作。标记为“readonly”的变量可以在构造函数中设置,并且其只读性也在运行时进行执行。这样做会带来一些轻微的性能损耗,但这意味着您可以将readonly与任何类型(甚至是引用类型)一起使用。

另外,const变量本质上是静态的,而readonly变量则可以根据需要是实例特定的。


添加常量是强类型的#define宏。否则,我们可能会吓跑所有C或C++程序员。 :-) - Jason Baker

5

在C#.Net中,const字段和readonly字段之间有明显的区别。

const默认为静态字段,并且需要使用常量值进行初始化,以后无法修改该值。构造函数中也不允许更改此值。它不能与所有数据类型一起使用。例如DateTime。不能与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可以被声明为静态的,但不是必需的。在声明时无需初始化。其值可以通过构造函数分配或更改。因此,当用作实例类成员时,它具有优势。两个不同的实例化可能具有不同的readonly字段值。例如 -

class A
{
    public readonly int Id;

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

只读字段可以使用以下方式初始化为特定的值:

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

在这里,实例objOne将具有只读字段的值为5,而objTwo的值为10。这是使用const不可能实现的。


3

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接