编译器错误CS0283指示只能将基本POD类型(以及字符串,枚举和空引用)声明为const。有人对这种限制的原理有理论吗?例如,能够声明其他类型的const值(如IntPtr)会很好。
const
我相信constC#的概念实际上是语法糖,它只是用文字值替换了名称的任何用法。例如,给定以下声明,任何对Foo的引用都将在编译时替换为“ foo”。
const string Foo = "foo";
这将排除任何可变类型,因此也许他们选择了此限制,而不必在编译时确定给定类型是否可变?
根据C#规范的第10.4章-常量: (C#3.0规范为10.4,在线版本为2.0的10.3)
常量是表示常量值的类成员:可以在编译时计算的值。
基本上说,您只能使用仅包含文字的表达式。不能使用对任何方法,构造函数的调用(不能用纯IL文字表示),因为编译器无法在编译时执行该执行,从而无法计算出结果。另外,由于没有方法将方法标记为不变式(即,输入和输出之间存在一对一的映射),因此编译器执行此操作的唯一方法是要么分析IL以查看是否它取决于输入参数以外的东西,特殊情况下处理的某些类型(例如IntPtr),或者只是不允许每次调用任何代码。
作为示例,IntPtr尽管是一种值类型,但它仍然是一种结构,而不是内置文字之一。因此,任何使用IntPtr的表达式都需要调用IntPtr结构中的代码,这对于常量声明是不合法的。
我能想到的唯一合法的常量值类型示例将是一个仅通过声明用零初始化的示例,这几乎没有用。
至于编译器如何处理/使用常量,它将使用计算所得的值代替代码中的常量名称。
因此,您具有以下效果:
if (SomeClass.Version == 1)
换句话说,在以下情况下:
在这种情况下,程序集B以其编译形式仍将值1与1进行比较,因为在编译程序集B时,常量的值为1。
实际上,如果仅使用程序集B中程序集A的所有内容,则将在不依赖程序集A的情况下编译程序集B。在程序集B中执行包含该表达式的代码不会加载程序集A。
因此,常数只能用于永远不会改变的事物。如果它是一个将来可能会更改的值,并且您不能保证同时重建所有其他程序集,则只读字段比常量更合适。
这样就可以了:
虽然不是:
编辑2016年5月27日
好的,刚刚收到了赞成票,所以我在这里重新阅读了我的回答,但这实际上是错误的。
现在, 打算 在C#语言规范的是我上面写的一切。您不应该使用不能用文字表示的东西const。
但是可以吗 嗯,是....
让我们看一下decimal类型。
decimal
public class Test { public const decimal Value = 10.123M; }
让我们看一下用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
是的,a const decimal实际上是readonly decimal。
const decimal
readonly decimal
这里真正的问题是编译器将使用它DecimalConstantAttribute来发挥其魔力。
DecimalConstantAttribute
现在,这是我在C#编译器中唯一了解的魔术,但我认为值得一提。