在.NET中,为什么在编译时而不是在JIT时评估常量?

时间:2010-12-10 23:36:26

标签: c# .net const

今天,当我在静态类中更改公开可见常量的值,然后用新编译的版本替换了程序集的旧副本时,我有点意外。令人惊讶的是,引用程序集的现有程序没有获取常量的新值。也就是说,我没有重新编译可执行文件,而只是替换了那个程序集。

我的实验的完整描述位于How constant is a constant?

我承认对此行为感到非常惊讶。我理解发生了什么,但我不明白为什么。是否有一个特殊的技术原因导致常量不能在JIT时间而不是编译时间被选中?是否存在这样做会破坏事情的情况?

2 个答案:

答案 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);}}
}