【问题标题】:In .NET, why are constants evaluated at compile time rather than at JIT time?在 .NET 中,为什么在编译时而不是在 JIT 时评估常量?
【发布时间】:2010-12-10 23:36:25
【问题描述】:

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

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

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

【问题讨论】:

  • 这是在太多书籍、博文中讨论过的行为,所以其实并不奇怪:)
  • @Lex:奇怪的是,我以前从未讨论过它。不过,我仍然想知道为什么
  • 我仍然不明白将它烘焙到 using 程序集中有什么好处。

标签: c# .net constants


【解决方案1】:

常量应该是常量。对于所有时间。常数是诸如 pi 的值或铅原子中的质子数之类的东西。

如果你的常量发生变化,它并不是真正的常量;请改用只读字段。

另请参阅框架设计指南,其中指出:

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

本质上,更改常量而不重新编译依赖它的所有内容就像更改方法的签名而不重新编译依赖它的所有内容一样糟糕。编译器在编译依赖程序集时会“纳入”关于来自引用程序集的元数据信息的各种假设。如果您进行任何更改,您不能指望事情会继续工作。

【讨论】:

  • @Jim:我不知道。首先,有六个或更多的 JIT 编译器,而我对它们都不是专家。其次,JIT 编译器经常根据运行时发生的事情来改变他们的行为,比如是否附加了调试器。第三,如果您关心性能,请双向编写代码,运行它,看看是否可以衡量差异。如果差异太小而无法衡量,那么这可能不是您首先应该担心的差异。
  • 我听说 PI 现在正好是 3。
  • @ChaosPandion:在一个六边形是圆的世界里,当然。
  • @Eric,我最近才意识到你的工作,我最近遇到的你的东西越多,我发现你的 stackoverflow 帖子就越棒,保持真棒:-P。
  • @ChaosPandion - 有人告诉我,总是使用较小的 PI 会更健康,我不得不承认,我的周长过大有问题 - 但我坚持使用原来的,无论多么不合理
【解决方案2】:

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

public static string ConstString {get{return "First test";}}

这具有只读字段的版本控制语义,但如果 jitter 将 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);}}
}

【讨论】:

    猜你喜欢
    • 2016-08-30
    • 2019-05-23
    • 2020-10-01
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 2023-03-18
    • 2014-12-21
    • 2015-09-10
    相关资源
    最近更新 更多