C# 在.NET中,为什么常量是在编译时而不是在JIT时计算的?

C# 在.NET中,为什么常量是在编译时而不是在JIT时计算的?,c#,.net,constants,C#,.net,Constants,今天,当我在一个静态类中更改了一个公共可见常量的值,然后用新编译的版本替换了程序集的一个旧副本时,我有点吃惊。令人惊讶的是,引用程序集的现有程序没有获取常量的新值。也就是说,我没有重新编译可执行文件,只是替换了一个程序集 关于我的实验的完整描述载于 我承认我对这种行为感到非常惊讶。我明白发生了什么,但我不明白为什么。为什么不能在JIT时间而不是编译时间提取常量,有什么特别的技术原因吗?是否存在这样做会破坏事物的情况?常量应该是常量。永远。常数是π的值,或铅原子中质子的数量 如果你的持续变化,它实

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

关于我的实验的完整描述载于


我承认我对这种行为感到非常惊讶。我明白发生了什么,但我不明白为什么。为什么不能在JIT时间而不是编译时间提取常量,有什么特别的技术原因吗?是否存在这样做会破坏事物的情况?

常量应该是常量。永远。常数是π的值,或铅原子中质子的数量

如果你的持续变化,它实际上不是一个持续变化的;改为使用只读字段

另请参见框架设计指南,其中说明:

对永远不会更改的常量使用常量字段。编译器将常量字段的值直接烧录到调用代码中。因此,如果不冒破坏兼容性的风险,const值永远无法更改


本质上,在不重新编译依赖于常数的所有内容的情况下更改常数与在不重新编译依赖于常数的所有内容的情况下更改方法的签名一样容易出错。编译器在编译依赖程序集时“烘焙”有关引用程序集元数据信息的各种假设。如果您做了任何更改,就不能指望事情继续工作。

还有第三种方法可以声明“常量”:公共静态属性

public static string ConstString {get{return "First test";}}
这具有只读字段的版本控制语义,但如果抖动内嵌到getter中,它将成为jit时间常数。与
const
不同,它可以用于用户定义的类型

我认为对值类型和字符串使用静态属性是一个好主意,但对用户定义的类不这样做,因为您不想在每个属性访问上分配一个新实例

我在我的固定点类型中使用了如下:

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);}}
}
公共结构固定点
{
私人int raw;
私有常量分形位数=16;
私有固定点(int-raw)
{
这个.raw=raw;
}
公共静态固定点零{get{返回新的固定点();}}

publicstaticfixedpoint One{get{返回新的FixedPoint(1@Jim:我不知道。首先,有五六个或更多的JIT编译器,我对其中任何一个都不是专家。其次,JIT编译器通常会根据运行时发生的情况改变其行为,例如是否附加了调试器。第三,如果您关心性能,请编写两种方式的代码,运行它,然后查看是否可以更改可以测量差异。如果差异太小而无法测量,那么这可能不是你首先应该担心的差异。我听说圆周率现在正好是3。@ChaosPandion:在六边形是圆的世界里,当然。@Eric,我最近才意识到你的工作,我最近接触到的你的东西越多,我就越敬畏你有些我发现了你的stackoverflow帖子,继续写下去吧:-P.@ChaosPandion-有人告诉我,圆周率越小越健康,我不得不承认,我的周长太大有问题-但我坚持原著,不管这是一种在太多书、博客帖子中讨论过的行为,所以它不是令人惊讶的是:)@Lex:奇怪的是,我以前从未遇到过关于它的讨论。不过我仍然想知道为什么。我仍然不知道将它烘焙到使用程序集中有什么好处。