为什么const不能在静态构造函数中初始化?为什么 const 是在编译时精确初始化的?这个过程是如何发生的?

问题描述 投票:0回答:1

const 在编译时初始化,其余在运行时初始化:在类调用时静态,其他字段(非静态)在实例创建时初始化。 问题:为什么 const 在编译时初始化?它们是静态的,为什么不能在静态构造函数中为它们赋值?

一般来说这是如何发生的? 如果const被初始化,那么就需要参考类来理解const原则上存在于其内部并读取它们的值,因此static也应该被计算并初始化,以及静态构造函数。但显然这不会发生,所以没有对该类的引用?那么 const 的值是如何读取的,为什么我们不能在不引用类的情况下访问它们呢? 例如:Console.WriteLine(MyClass.PI)? 为什么我们不能:Console.WriteLine(PI)?因为不知道PI在哪里。那么编译器在不知道 PI 在哪里、原则上也不知道 PI 存在的情况下,如何在不访问类的情况下在编译阶段输入值呢?

constants visual-studio-2022
1个回答
0
投票

有多种方法可以实现这一点,但在 .Net 下的 C# 中,常量会在代码转换为 IL 代码(类似于汇编语言,成为 .Net 实际运行的字节码)之前插入代码中。 .

我使用了一个名为 LINQPad8 的工具来分析这种情况的一个简单示例:

class Program
{
    private const int VALUE = 10;
    
    static void Main(string[] args)
    {
        int value1 = 10;
        Console.WriteLine(value1);

        int value2 = VALUE;
        Console.WriteLine(value2);

        Console.WriteLine(VALUE);
    }
}

在使用 LINQPad 用来完成工作的 .Net 工具 ILSpy 分析代码之前,该常量已经从代码中进行了预处理,生成以下内容:

 int value1 = 10;
 Console.WriteLine (value1);
 int value2 = 10;
 Console.WriteLine (value2);
 Console.WriteLine (10);

所有这些都变成了以下 CLR IL 代码:

IL_0000 nop 
IL_0001 ldc.i4.s    0A  // 10
IL_0003 stloc.0    // value1
IL_0004 ldloc.0    // value1
IL_0005 call    Console.WriteLine (Int32)
IL_000A nop 
IL_000B ldc.i4.s    0A  // 10
IL_000D stloc.1    // value2
IL_000E ldloc.1    // value2
IL_000F call    Console.WriteLine (Int32)
IL_0014 nop 
IL_0015 ldc.i4.s    0A  // 10
IL_0017 call    Console.WriteLine (Int32)
IL_001C nop 
IL_001D ret 

特别是在最后一次调用中,常量 VALUE 直接用作调用 Console.WriteLine(Int32) 的参数,没有访问在内存中存储变量的指令,即对 stloc 和 ldloc 的调用。

整数 0x0A(十进制为 10)作为 32 位有符号整数直接压入堆栈,这就是向方法调用提供参数的方式。 另外两个调用显示了使用变量并将其压入堆栈时的外观。

© www.soinside.com 2019 - 2024. All rights reserved.