今天,当我在静态类中更改公开可见常量的值,然后用新编译的版本替换了程序集的旧副本时,我有点意外。令人惊讶的是,引用程序集的现有程序没有获取常量的新值。也就是说,我没有重新编译可执行文件,而只是替换了那个程序集。
我的实验的完整描述位于How constant is a constant?
我承认对此行为感到非常惊讶。我理解发生了什么,但我不明白为什么。是否有一个特殊的技术原因导致常量不能在JIT时间而不是编译时间被选中?是否存在这样做会破坏事情的情况?
答案 0 :(得分:30)
常量应该是常量。对于所有时间。常数是像pi的值,或者在铅原子中的质子数。
如果你不断变化,它实际上不是一个常数;改为使用只读字段。
另请参阅框架设计指南,其中说明:
对永远不会改变的常量使用常量字段。编译器将const字段的值直接烧录到调用代码中。因此,在不存在破坏兼容性的风险的情况下,永远不能更改const值。
本质上,更改常量而不重新编译依赖于它的所有内容,就像更改方法的签名而不重新编译依赖于它的所有内容一样。编译器在编译依赖程序集时,会从引用的程序集中“加入”有关元数据信息的各种假设。如果您进行任何更改,您就不能指望事情继续发挥作用。
答案 1 :(得分:1)
还有第三种方法来声明“常量”:公共静态属性。
public static string ConstString {get{return "First test";}}
这具有只读字段的版本控制语义,但如果抖动内联getter,则它变为jit-time常量。与const
不同,它可以用于用户定义的类型。
我认为对值类型和字符串使用静态属性是个好主意,但对于用户定义的类则不行,因为您不希望在每个属性访问上分配新实例。
我在我的FixedPoint类型中使用了这个:
public struct FixedPoint
{
private int raw;
private const fracDigits=16;
private FixedPoint(int raw)
{
this.raw=raw;
}
public static FixedPoint Zero{get{return new FixedPoint();}}
public static FixedPoint One{get{return new FixedPoint(1<<fracDigits);}}
public static FixedPoint MaxValue{get{return new FixedPoint(int.MaxValue);}}
}