来自C# 规范,第 10.4 章 - 常量:
(C# 3.0 规范中为 10.4,2.0 在线版本中为 10.3)
常量是表示常量值的类成员:可以在编译时计算的值。
这基本上意味着您只能使用仅由文字组成的表达式。不能使用对任何方法、构造函数(不能表示为纯 IL 文字)的任何调用,因为编译器无法在编译时执行该执行,从而计算结果。另外,由于无法将方法标记为不变(即输入和输出之间存在一对一映射),因此编译器执行此操作的唯一方法是分析 IL 以查看是否它取决于输入参数以外的其他因素,特殊情况处理某些类型(如 IntPtr),或者只是禁止对任何代码的每次调用。
例如,IntPtr 虽然是一种值类型,但仍然是一种结构体,而不是内置文字之一。因此,任何使用 IntPtr 的表达式都需要调用 IntPtr 结构中的代码,这对于常量声明来说是不合法的。
我能想到的唯一合法的常量值类型示例是通过声明它来用零初始化的示例,但这几乎没有用。
至于编译器如何处理/使用常量,它将使用计算值来代替代码中的常量名称。
因此,您将获得以下效果:
- 没有对原始常量名称、声明它的类或命名空间的引用编译到此位置的代码中
- 如果反编译代码,它将包含幻数,因为如上所述,对常量的原始“引用”不存在,只有常量的值
- 编译器可以使用它来优化,甚至删除不必要的代码。例如,
if (SomeClass.Version == 1)
,当 SomeClass.Version 的值为 1 时,实际上会删除 if 语句,并保留正在执行的代码块。如果常量的值不为 1,则整个 if 语句及其块将被删除。
- 由于常量的值被编译到代码中,而不是对常量的引用,因此如果常量的值发生变化(不应该发生变化!),使用其他程序集中的常量将不会以任何方式自动更新已编译的代码。
换句话说,有以下场景:
- 程序集 A,包含名为“Version”的常量,值为 1
- 程序集 B,包含一个表达式,该表达式根据该常量分析程序集 A 的版本号并将其与 1 进行比较,以确保它可以与该程序集一起使用
- 有人修改了程序集 A,将常量的值增加到 2,并重建了 A(但不是 B)
在这种情况下,程序集 B 在其编译形式下仍会将 1 与 1 的值进行比较,因为编译 B 时,常量的值为 1。
事实上,如果这是程序集 B 中程序集 A 中的任何内容的唯一用法,则程序集 B 将在不依赖于程序集 A 的情况下进行编译。在程序集 B 中执行包含该表达式的代码将不会加载程序集 A。
因此,常量只能用于永远不会改变的事物。如果它是一个可能或将在将来某个时间更改的值,并且您不能保证所有其他程序集同时重建,则只读字段比常量更合适。
所以这是可以的:
- 公共常量 Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
- 公共常量 Int32 NumberOfHoursInADayOnEarth = 24;
虽然这不是:
- 公共 const Int32 AgeOfProgrammer = 25;
- public const String NameOfLastProgrammerThatModifiedAssembly = "乔程序员";
2016 年 5 月 27 日编辑
好的,刚刚得到了赞成票,所以我在这里重新阅读了我的答案,这实际上有点错误。
现在意图C# 语言规范的内容就是我上面写的所有内容。你不应该使用无法用文字表示的东西作为const
.
但你可以吗?嗯,是....
让我们看一下decimal
type.
public class Test
{
public const decimal Value = 10.123M;
}
让我们看看这个类是什么样子的really当用 ildasm 观察时:
.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00 )
让我为你分解一下:
.field public static initonly
对应于:
public static readonly
没错,一个const decimal
实际上是一个readonly decimal
.
这里真正的问题是编译器将使用它DecimalConstantAttribute
发挥其魔力。
现在,这是我所知道的 C# 编译器的唯一这样的魔力,但我认为它值得一提。