一个静态类中const、readonly和get有什么区别?

21

我有一个问题。最近我发现自己在使用三行代码,仔细检查后它们看起来感觉相同。

public static class constant
{
    public static readonly int val1 = 5;
    public const int val2 = 5;
    public static int val3 { get { return 5; } }
}

我的问题是,它们是相同的吗?是否应该优先使用其中之一?如果是这样,请问何时使用?

另外,额外的问题是:在 Visual Studio 中为什么它们在智能感知中的表示方式都不同?

在此输入图像描述

7个回答

10
声明为readonly的成员变量可以在类的(静态)构造函数中被更改,而const成员变量在运行时不能更改。
将字段声明为const会自动使其成为静态常量,引用自§10.3.7:
“当字段、方法、属性、事件、运算符或构造函数声明包括static修饰符时,它声明一个静态成员。此外,常量或类型声明隐式声明一个静态成员。”
第三个是只读属性,总是返回5。
尽可能使用const成员,以便允许编译器和/或JIT执行其优化,并帮助其他人阅读您的代码(该属性对我来说有点奇怪)。 如果需要在程序启动期间初始化常量值(例如,机器核心数),则必须使用静态readonly成员。
这是C#规范(§10.5.2.1)的一个很好的例子:
“当需要符号名称表示常量值,但值的类型不允许在const声明中使用,或者值无法在编译时计算时,静态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;
    }
}

黑色、白色、红色、绿色和蓝色成员不能被声明为常量成员,因为它们的值无法在编译时计算。然而,将它们声明为静态只读字段具有相同的效果。
另外一个不同之处是:常量和只读字段具有不同的二进制版本控制语义。当表达式引用常量时,常量的值在编译时获取,但当表达式引用只读字段时,字段的值直到运行时才会获取。
总之,尽管乍一看它们可能看起来相似,但它们非常不同,您应该使用最适合您意图的那个。

1

您好,您将在此帖子中找到有关您问题的答案:

静态只读 vs 常量

您还可以检查IL代码并尝试自行比较结果。


2
不解释Visual Studio图标和获取示例。 - Thomas Andreè Wang

0

静态只读字段可以在构造函数中赋值,而常量则不行。此外,getter 不必返回一个常量值,该值可以是一个私有成员,在类的另一部分中可以更改,或者是一个计算出来的值。

参见 C# 参考中的 readonly

readonly 关键字与 const 关键字不同。const 字段只能在字段声明时初始化。readonly 字段可以在声明时或构造函数中初始化。因此,readonly 字段可以根据使用的构造函数具有不同的值。此外,虽然 const 字段是编译时常量,但 readonly 字段可用于运行时常量,如以下示例所示:

public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

readonly 关键字是一个修饰符,可以用于字段。当字段声明包括 readonly 修饰符时,通过声明引入的字段的赋值只能作为声明的一部分或在同一类中的构造函数中发生。
来自 C# 参考
const 关键字用于修改字段或局部变量的声明。它指定字段或局部变量的值是常量,这意味着它不能被修改。
此外,它们在智能感知中也有所不同,因为它们是不同的编译时对象。

1
这并没有回答问题。 - AgentFire

0

在编程中,尽可能使用const常量字段 - 但这仅适用于原始类型。

当您需要自定义类型(例如您自己的类或结构)时,应使用public static property

公共字段仅用于结构体中,我无法回忆起任何情况下看到任何公共静态只读字段。


string.Empty 是一个 public static readonly 字段。 - Federico Berasategui
Type.MissingType.EmptyTypes等等都是公共的静态只读字段的例子。 - Sriram Sakthivel

0

当您在字段定义中使用constreadonly时,const限定符只能与原始数据类型和字符串一起使用。使用时,分配给const字段的值直接插入到生成的IL代码中的所有引用中。这也适用于其他程序集。引用该const字段的其他程序集将被编译为如果它们直接使用了该值本身。Readonly字段是运行时常量。它们占用内存中的某些位置,并且对它们的引用在运行时解析,就像我们引用普通变量一样。实际上,它们是类似常量的变量。

const:

通常情况下,尽量避免使用常量,因为该值不仅硬编码到声明它们的程序集中,而且还硬编码到引用常量值的任何程序集中。这可能会导致一些真正奇怪的问题。

  • 不能是静态的。
  • 值在编译时计算。
  • 只能在声明时初始化。

readonly:

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

0

常量是在编译时评估的表达式。编译器可以直接将该值嵌入到使用它的每个位置。静态只读仅在运行时评估,并且如果您认为该值稍后可能会更改,它很有用,因为针对您编译的程序集不会嵌入静态只读值,这可能会发生在 const 中。请注意,一些值(例如 DateTime.Now)无法存储在常量中,因为它是必须在运行时完成的属性评估。您可以使用静态只读,它类似于 const,但它将捕获运行时的值。

最后一个是一个可以做更多事情而不仅仅返回值的属性。它可能是 Web 服务调用或复杂计算的结果。请注意,属性中的代码可能会被编译器内联

您使用哪个取决于您想要的语义。


0

我来解释一下你的第一个问题。

Const(常量):成员在编译时应该给定初始值,然后它们就不能被更改。Static readonly(静态只读):成员的值不必被分配以进行初始化,然后再被分配。一旦指定,就不能更改。

可以从所属类中访问静态只读成员,并且可以分配值。必须对成员赋值进行第一次赋值,或者在事务中进行静态构造函数。


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