重新编译引用的程序集时不变的常量值

我在汇编中有这个代码:

public class Class1 { public const int x = 10; } 

在我有一个不同的集会:

 class Program { static void Main(string[] args) { Console.WriteLine(Class1.x); Console.ReadKey(); } } 

当然输出是10 ,但后来我把x改为20

 public class Class1 { public const int x = 20; } 

我重新编译了程序集并将其移动到我的命令行程序的bin目录中。 但是,我的程序输出仍然是10 ,直到我编译包含main函数的程序集。

为什么会这样?

C#中的常量值在使用它们的位置内嵌。 即行Console.WriteLine(Class1.x); 将被编译为Console.WriteLine(10); 。 生成的IL代码如下所示:

  .entrypoint .maxstack 8 IL_0000: nop IL_0001: ldc.i4.s 10 // here just integer value 10 is loaded on stack IL_0003: call void [mscorlib]System.Console::WriteLine(int32) 

没有任何指向Class1的链接。 因此,在重新编译Main集之前,它将具有内联值10 。 MSDN警告这种常量使用情况:

不要创建常量来表示您希望随时更改的信息。 例如,不要使用常量字段来存储服务价格,产品版本号或公司的品牌名称。 这些值可能会随着时间的推移而发生变化,并且由于编译器传播常量,因此必须重新编译使用库编译的其他代码以查看更改。

他们提到仅在编译时评估常量表达式。 即Class1.x将在Main集编译时评估为值10 。 如果没有重新编译,那么价值就不会改变。 但不幸的是,它并没有清楚地解释这种行为的原因(至少对我而言)。

BTW Named和Optional参数值也在调用方法的位置进行内联,您还需要重新编译调用程序程序集以更新值。

这是一种在编译时使用的称为常量折叠的技术。 简而言之,编译器会查找可在编译时确定的值,计算这些值,并直接在exe文件中写入它们。 这加速了最终机器代码的执行。 此技术也适用于其他许多编译语言,例如C,C ++。