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

本文关键字:常量 程序集 新编译 编译 引用 | 更新日期: 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++。