重新编译引用程序集时不更改的常量值
本文关键字:常量 程序集 新编译 编译 引用 | 更新日期: 2023-09-27 18:08:52
我在程序集中有以下代码:
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命名参数和可选参数值也内联在调用方法的地方,您还需要重新编译调用程序集来更新值。
这是一种称为常量折叠的技术用于编译。简而言之,编译器查找可以在编译时确定的值,计算这些值,并将它们直接写入到exe文件中。这加快了最终机器码的执行速度。此技术也适用于其他许多编译语言,如C、c++。