字符串常量在.Net中嵌入两次?

说我有一个简单的(最简单的?)C#程序:

class Program { static void Main() { System.Console.WriteLine("Hello, world"); } } 

如果,我编译该代码并查看生成的.exe,我按预期在exe图像中看到“Hello,world”字符串。

如果我重构代码:

 class Program { const string Greeting = "Hello, world"; static void Main() { System.Console.WriteLine(Greeting); } } 

如果我编译该代码并查看生成的.exe,我会在exe映像中看到两次“Hello,world”字符串文字。 这对我来说很惊讶。 我的印象是字符串文字是共享的,因此它只会出现在图像中一次。 有谁能解释一下? 也许reflection元数据需要第二个字符串副本?

ECMA-335 CLI规范对此有所了解。 AC# const在IL中声明为static literal字段。 从第I.8.6.1.2节(强调我的):

文字约束承诺位置的值实际上是内置类型的固定值。 该值被指定为约束的一部分。 编译器需要用其值替换对该位置的所有引用,因此VES不需要为该位置分配空间。 此约束虽然在逻辑上适用于任何位置,但只能放置在复合类型的静态字段上。 如此标记的字段不允许从CIL引用(它们应在编译时内联到它们的常量值),但可以使用直接处理元数据的reflection和工具来使用。

因此,编译器获取常量值并在整个代码中替换它。 不允许引用常量存储。 它从那里做的是它对任何其他文字字符串的作用。 它在元数据表中为它提供了一个插槽,并使用ldstr操作代码来加载字符串。 因此,值在程序集中出现两次。 一旦进入常量的存储位置,就不能被兼容的编译器引用。 还有一次在元数据表中。