【问题标题】:Why are private constants stored in .NET assemblies?为什么私有常量存储在 .NET 程序集中?
【发布时间】:2014-11-07 22:43:35
【问题描述】:

代码引用的常量在编译成 IL 时会被它们的实际值替换。

由于公共常量可以被特定程序集之外的代码引用,因此将它们存储在程序集的元数据中是有意义的。

但是为什么私有常量存储在那里?在定义它们的程序集的代码的 IL 中没有对这些常量的引用,并且它们不会被公开在程序集之外被引用。

那么在编译完代码后需要访问这些值吗?

在我看来,程序集中的所有常量都应该是公共的,而私有常量应该是一种语言级别的功能,它只会导致编译器发出文字值。

【问题讨论】:

  • 因为 BindingFlags.NonPublic。当您陷入困境并且程序员没有拿起电话来帮助您时,能够戳私处非常方便。
  • 但是访问那个私有常量有什么用呢?没有 IL 引用该常量。所有这一切都告诉你有人决定使用常量而不是在某处硬编码一个值。
  • 当然是“IL 引用该常量”。它嵌入在IL中。如果你永远找不到它的用途,那么生活就是美好的。
  • 我的意思是使用常量的代码和使用文字的代码之间的 IL 没有区别。换句话说,声明(在 C# 中)private const string MYCONST = "Hello World" 然后执行 Console.WriteLine(MYCONST) 导致与执行 Console.WriteLine("Hello World") 相同的 IL。

标签: .net .net-assembly il


【解决方案1】:

C# 编译器可以优化掉各种私有的东西。不仅仅是常数。它可以删除未使用的成员、类、代码。它可以剥离私人名称。它可以删除私有属性并用方法替换它们。等等

反射访问和 IL 重写工具被认为是私有内容的重要用例。此外,当大多数元数据仍然存在时,调试会更容易。例如,您可以使用 Edit&Continue 来使用以前未使用的成员。您可以使用即时窗口调用静态未使用的成员。

也许对 PDB 符号也有影响,尽管我现在想不出来。

请注意,.NET 程序集包含许多对反射访问有用的元数据。除了可检查之外,属性根本没有运行时影响。程序集应该是丰富的和自我描述的。

有人可能会争辩说,保留常量特别无用,因为它们总是静态未使用。然而,这并不意味着它们没有反射用途。他们还可以帮助反编译代码。智能反编译器可能会注意到某个文字与附近声明的常量相同。此外,为什么要对常量进行例外以优化它们呢?典型程序中的常量很少。即使假设移除它们会更好,投资也很难得到回报。同时更好地开发有用的语言功能。

【讨论】:

  • Reflection 可以告诉您使用了一个常量,但在任何 IL 代码中都没有引用该常量。编译器已经通过在引用的地方注入文字来“优化”常量。其他私有成员可以通过反射访问,因此将有关它们的信息存储在元数据中是有意义的。但是你从常量中得到的只是程序员决定使用它们的知识。属性是公共的,并且意味着可以通过编程方式访问以影响逻辑,即使它们不会自动这样做。
  • 猜测具有匹配值的文字引用相同的常量太容易出错。例如,如果我声明一个常量private const int SCHEMAVERSION = 1,那么反编译器会将这个代码var x = myarray[myarray.Length - 1] 映射到这个var x = myarray[myarray.Length - SCHEMAVERSION]。然后在某些情况下,我可能会引用外部公共常量,即使局部常量具有相同的值。如果他们想支持这一点,我会认为他们会有对常量的 IL 指令支持,然后让抖动注入文字。
  • 至于优化它们所需的额外努力,真的没有。如果他们将 IL 常量设为仅公开,那么语言只需将语言定义的公共常量添加到元数据中即可。艰苦的工作是用文字替换所有对常量的引用,这是规范所要求的。对我来说,他们会强制执行类似的操作,然后不将常量定义为仅限公共,这对我来说似乎很奇怪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 2021-10-17
  • 2013-12-24
  • 2010-09-06
  • 2011-10-15
  • 2015-03-01
相关资源
最近更新 更多