在C#中常量和只读之间有什么区别?

你什么时候会用一个代替另一个?


当前回答

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

但如果使用常量,则在编译调用者时,它将被折叠到调用者的代码中。

如果你已经达到了C#的熟练程度,你就可以阅读比尔·瓦格纳的书《有效的C#:提高你的C语言的50种具体方法》了#它详细回答了这个问题(以及其他49个问题)。

其他回答

常量

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

只读实例字段

在构造函数退出时必须具有设置值在创建实例时计算

静态只读字段

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

它们都是常量,但在编译时也可以使用常量。这意味着差异的一个方面是,可以使用常量变量作为属性构造函数的输入,但不能使用只读变量。

例子:

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

何时使用常量或只读常量编译时常量:绝对常量,值在声明期间设置,在IL代码本身中只读的运行时常量:可以通过配置文件(即App.config)在构造函数/init中设置,但一旦初始化就不能更改

Const和readonly相似,但并不完全相同。const字段是一个编译时常量,意味着该值可以在编译时计算。只读字段支持在构造类型期间必须运行某些代码的其他场景。构造后,无法更改只读字段。

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

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

因为像3.14和0这样的值是编译时间常数。然而,请考虑这样的情况:您定义了一个类型,并希望提供它的一些预制实例。例如,您可能希望定义一个Color类,并为常见颜色(如黑色、白色等)提供“常量”。不可能使用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的客户破坏它,可能是通过交换Black和White值。不用说,这会给Color类的其他客户端带来恐慌。“只读”功能解决了这种情况。通过在声明中简单地引入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成员总是静态的,而只读成员可以是静态的,也可以不是静态的,就像常规字段一样。

可以将一个关键字用于这两个目的,但这会导致版本控制问题或性能问题。假设我们对这个(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代替?如果你对此说“是”,那么这意味着A的开发者不能改变A.C的初始化方式——这在未经许可的情况下束缚了A的开发者的双手。如果你对这个问题说“不”,那么就会错过一个重要的优化。也许A的作者肯定A的C值永远为零。const和readonly的使用允许A的开发人员指定意图。这有助于更好的版本控制行为和更好的性能。

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