重新编译引用的程序集时不变的常量值
我在汇编中有这个代码:
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 ++。