【问题标题】:Why are c# constants substituted为什么 c# 常量被替换
【发布时间】:2016-01-15 00:33:24
【问题描述】:

我们知道很多关于常量的事情:

  • 值必须在编译时已知
  • 值永远不能在运行时更改
  • 它们被推送到声明程序集元数据中
  • 所有出现都被其在 IL 中的值替换
  • 它们可能会造成严重的跨程序集版本控制问题
  • 它们不消耗动态内存,因为它们的值在 IL 代码中被替换
  • 常量只能是原始类型 + 任何初始化为 null 的引用类型(MSDN 没有提到这部分)

除了常量的基本特征之外,为什么 clr 团队决定用文字代替常量值的每次出现?在我看来,抖动将完全能够将包含的程序集加载到内存中,在元数据中搜索类型并提取正确的最新值。

我真的不相信这里的性能是一个问题,在任何代码中都没有那么多值得这样做的常量。更不用说包含常量的程序集的经典版本控制问题了。

通过 C# 的 CLR 应该给我一个过度的答案,但它没有。

【问题讨论】:

  • 因为它们是常量,所以发出最终将在本机转换为 mov ax, 1234h 的代码最终比一直进行查找更快、更有效。立即寻址比间接寻址更快
  • “它们可能会造成严重的跨程序集版本控制问题” - 前提是您不重新编译所有内容。一般来说,在这个尽职尽责的 TDD 时代,人们无论如何都应该使用构建服务器;和 CI 服务器,而不是从你的 DEV 盒子部署,这是我能想到的唯一方法,你会遇到这样的问题。
  • "natively 最终比一直查找更快、更高效" 字节码不应该一直查找值。在我看来,可以在 jitting 到字节码而不是编译到 IL 时替换常量值。性能不会成为问题,因为每个引用程序集都需要在 jitted 时访问定义程序集一次。这就是我优雅地自相矛盾的地方:) 这种方式几乎每次出现都必须查找并替换为字节码,因为抖动通常发生在方法级别。
  • 所以,是的,这里可能存在性能问题,但我仍然认为这无关紧要,因为常量值的使用远不像使用普通旧值类型那样普遍,当一个发明价值类型的主要目的是性能。

标签: c# clr constants


【解决方案1】:

常量有问题,你把它命名为:“所有出现的地方都用它在 IL 中的值代替”。

假设您有一个包含两个项目的解决方案,一个控制台应用程序(项目 A)和一个用于 DAL/基础设施的核心 DLL(项目 B),例如

在您的项目 B 中,您将 TaxRate 常量定义为值为 10 的 int,并在项目 A 中引用您的常量。

您构建(在 IL 中所有出现的常量都将替换为“10”的值。)并部署您的应用程序。

稍后,TaxRate 更改为 15,您只编译项目 B 并只替换现有应用程序中的 DLL - 这会起作用,对吗?

是的,不是的。它会起作用,因为你不会有任何错误——唯一改变的是 int 值。但是在您的控制台应用程序中,当您期望获得 15 的值时,您将获得 10 的值。为什么?因为当您第一次构建应用程序时,所有项目中的常量值都被替换了,并且您只替换了项目 B DLL 而不是项目 A。

在这种情况下,如果您更改为 public readonly int,您将不会遇到此问题。

希望这会有所帮助,

【讨论】:

  • 我不确定您所描述并由 OP 提示您在一个程序集中进行更改但未能重新编译和重新部署所有程序集的场景是否不现实也不负责任.我不确定我是否同意public readonly int 策略,因为它可以消除症状并且不能解决原因。即无法重建 CI 服务器上的所有内容。
  • 很抱歉,这个答案并没有解释为什么会发生替换的真正原因。
  • 另一方面,如果程序集版本控制得到妥善处理,我非常同意无法重新编译一个程序集是不太现实的。
猜你喜欢
  • 1970-01-01
  • 2013-09-10
  • 2013-12-28
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多