题 静态只读与const


我已经读过了 const 和 static readonly 领域。我们有一些只包含常量值的类。用于我们系统中的各种事物。所以我想知道我的观察是否正确:

应该是这些常数值 static readonly 对于一切公开的东西?而且只能使用 const 内部/受保护/私人价值?

你有什么建议?我甚至可能不会使用 static readonly 字段,但可能使用属性?


1204
2018-04-16 11:21


起源


这是一个非常有趣的单一案例,我刚刚赞成 static readonly: 尝试在一个内部使用const IEnumerator 哪会触发一个 unrecheable  yield 你会得到一个可怕的“内部编译器错误”。我没有在Unity3D之外测试代码,但我相信这是一个 单 要么 。净  窃听器。它是一个 C# 尽管如此。 - cregox
可能重复 const和readonly有什么区别? - nawfal
另一个区别是你可以在交换机中使用const字符串,但不能使用静态只读字符串 - flagg19
static readonly 不能用于 switch-case 声明为 case 变量, const 为此目的是必需的。 - mostafiz rahman
static readonly 也不能用作属性参数 - Dread Boy


答案:


public static readonly 田地有点不寻常; public static 属性(只有一个 get)会更常见(可能由一个 private static readonly 领域)。

const 值被直接刻录到呼叫站点;这是双刃:

  • 如果在运行时获取值,可能是从config获取它是没用的
  • 如果更改const的值,则需要重建所有客户端
  • 但它可以更快,因为它避免了方法调用...
  • ......无论如何,JIT有时可能已将其内联

如果值会 决不 改变,然后const很好 - Zero 做出合理的决定; p除此之外, static 属性更常见。


830
2018-04-16 11:24



为什么房地产?如果它是一个不可变的类,我认为没有区别。 - Michael Hedgpeth
@Michael - 和往常一样的理由;它隐藏了实施。您可能会发现(稍后)您需要延迟加载,基于配置,外观或其他任何内容。实际上,要么通常都很好...... - Marc Gravell♦
根据定义,@ CoffeeAddict是一个常数 不是 从配置文件中提取值;它在编译时作为文字刻录。唯一可以使用常量的方法 在运行时 通过对田野的反思。你尝试使用它的任何其他时间,编译器 已经取代你的 不变 用法 文字 用法;即如果代码中的方法使用6个常量,并将其检查为IL,则不会提及任何常量查找;字面值将简单地加载到原位 - Marc Gravell♦
@MarcGravell - 小心: readonly 字段不能在switch / case语句中使用,而是需要它们 const。 - Luciano
@Luciano:我明白你现在的意思,你可以打开只读变量,但你不能使用readonly变量。这是有道理的,但起初有点不清楚。 - MPavlak


我会用 static readonly 如果 消费者 在一个不同的集会。有了 const 和 消费者 在两个不同的集合中是一个很好的方法 射击自己的脚


200
2018-04-16 12:57



所以我认为,正如一些人已经提到或暗示的那样,如果将公用事物公开的值仅使用const作为实际众所周知的常量可能是明智的,否则它们应该保留用于内部,受保护或私有访问范围。 - jpierson
@Dio它仍然存在的原因是因为它本身不是一个问题 - 它需要注意,但是跨越程序集边界内联的能力对性能来说是一件好事。这真的只是一个真正理解“恒定”意味着“它永远不会改变”的问题。 - Michael Stum♦
@MichaelStum好吧我不应该把它称为“一个问题”。在我的工作中,我确实有const并在程序集之间共享它,但我为每个部署或代码发货重新编译。不过,这个事实绝对值得注意。 - Dio Phung
所以,总的来说, internal const 要么 public static readonly 取决于所需的可见性。 - Iiridayn
@Iiridayn是的,这不是一个看待它的坏方法。有一些边缘情况需要考虑(例如,如果使用Reflection,或者属性需要值),并且有一些有效的用途 public const (例如,标准的任何部分。无论何时我使用XML,都有一个带有一堆的命名空间文件 public const string。)但总的来说, public const 只有在适当考虑其影响后才能使用。 - Michael Stum♦


其他一些事情

const int a 

  • 必须初始化
  • 初始化必须在编译时

readonly int a

  • 可以使用默认值,而无需初始化
  • 初始化可以在运行时

173
2018-04-16 11:36



在...内 ctor 只要。 - Amit Kumar Ghosh


这只是对其他答案的补充。我不会重复它们(现在四年后)。

有些情况下 const 和非const有不同的语义。例如:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

打印出来 True,而:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

False

原因是该方法 x.Equals 有两个重载,一个接受一个 short (System.Int16并且需要一个 object (System.Object)。现在问题是一个或两个是否适用于我的 y 论据。

什么时候 y 是一个编译时常量(文字), const 在这种情况下,确实存在隐式转换变得很重要   int    short 只要那个 int 是一个常量,并且假设C#编译器验证其值是否在a的范围内 short (哪一个 42 是)。看到 隐式常量表达式转换 在C#语言规范中。因此必须考虑两种重载。超载 Equals(short) 是优选的(任何 short 是一个 object, 但不是所有的 object 是 short)。所以 y 转换为 short,并使用该重载。然后 Equals 比较两个 short 相同的价值,并给出 true

什么时候 y 不是常数,不是 含蓄 转换自 int 至 short 存在。那是因为一般而言 int可能太大了,不适合 short。 (一个 明确的 转换确实存在,但我没有说 Equals((short)y),这是不相关的。)我们看到只有一个重载适用, Equals(object) 一。所以 y 盒装到 object。然后 Equals 比较一个 System.Int16 到了 System.Int32,由于运行时类型甚至不同意,这将产生 false

我们得出结论,在一些(罕见的)情况下,改变一个 const 键入成员到 static readonly 字段(或其他方式,如果可能的话)可以改变程序的行为。


151
2017-09-11 14:52



对接受的答案的一个很好的补充。我想补充一点,数据类型和其他类似指南(如try catch等)的正确转换应该是有经验的程序员的主要内容,而不是留给编译器。不过,我从这里学到了新东西。谢谢。 - Uknight
哇,我已经用C#编程了很长时间,我从来没有想过短路范围内的const int可以隐式转换为short。我必须说这很奇怪。我喜欢C#,但这些奇怪的不一致似乎没有增加太多价值,但增加了许多必要的脑力来不断考虑可能会很烦人,特别是对于初学者。 - Mike Marynowski
@MikeMarynowski真的。但我认为他们制定了这一规则(以及其他原因) short x = 42; 法律。因为你有一个 int,即文字 42,这隐含地变成了 short x。但是,他们可能将这仅限于数字文字;然而,他们选择允许这样的事情 short x = y; 哪里 y 被定义为 const int y = 42;,然后他们最终得到了这个。 - Jeppe Stig Nielsen


有一点需要注意的是 常量 仅限于原始/值类型(字符串除外)


82
2018-04-16 11:28



其实 const 也可以用于其他类型,除了它必须初始化为null,这使得它无用:) - nawfal
例外情况 System.Exception? :) - Memet Olsen
@nawfal更确切地说,是唯一的 价值类型 为此 const 可以使用,是 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool加上任何 enum 类型。 const 不能用于其他值类型 DateTime 要么 TimeSpan 要么 BigInteger。它也不能用于 IntPtr struct(被某些人认为是“原始”类型;术语原始类型在C#中令人困惑)。 ↵↵ const 可以用于所有人 参考类型。如果类型是 string,可以指定任何字符串值。否则,值必须是 null。 - Jeppe Stig Nielsen
@JeppeStigNielsen - 我 最近有一个争论 同 servy 关于这一点 - 他指出你可以做到 什么 (价值和参考类型) const 运用 default。对于 struct 类型,它是一个实例,其所有成员都设置为默认值。 - Wai Ha Lee


readonly 关键字不同于 const 关键词。一个 const 字段只能在字段声明中初始化。一个 readonly 可以在声明或构造函数中初始化字段。因此, readonly 字段可以具有不同的值,具体取决于使用的构造函数。还有,一个 const field是一个编译时常量, readonly 字段可用于运行时常量

这里简短而明确的MSDN参考


23
2017-11-14 18:58





静态只读 : 价值可以改变 static 运行时的构造函数。但不是通过成员函数。

不变 : 默认 static。价值不能从任何地方改变(Ctor,Function,runtime等no-where)。

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

你可以看看我的回购: C#属性类型


16
2018-01-12 17:14



坏消息......破碎的链接! - Fer R
@FerR你去了: github.com/yeasin90/advanced-csharp/blob/master/CSharpAdvanced/... - Yeasin Abedin Siam