静态字段初始化如何在C#中工作?

Pra*_*ter 25 c# compiler-construction

是否应在调用构造函数之前完成静态字段初始化?

以下程序提供的输出似乎对我不正确.

new A()
_A == null
static A()
new A()
_A == A
Run Code Online (Sandbox Code Playgroud)

代码:

public class A
{
    public static string _A = (new A()).I();

    public A()
    {
        Console.WriteLine("new A()");
        if (_A == null)
            Console.WriteLine("_A == null");
        else
            Console.WriteLine("_A == " + _A);
    }

    static A()
    {
        Console.WriteLine("static A()");
    }

    public string I()
    {
        return "A";
    }
}

class Program
{
    static void Main(string[] args)
    {
       var a = new A();
    }
}
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 28

这是对的.

你的静态初始化器,然后静态构造函数在你的标准构造函数之前运行,但是当它运行时,它使用新的A(),所以通过你的非静态构造函数路径.这会导致您看到的消息.

这是完整的执行路径:

当您第一次调用var a = new A();程序时,这是第一次访问A.

这将触发静态初始化 A._A

此时,A._A构造着 _A = (new A()).I();

这点击


Console.WriteLine("new A()");
if (_A == null)
    Console.WriteLine("_A == null");        
Run Code Online (Sandbox Code Playgroud)

从那时起,_A尚未使用返回的构造类型(尚未)进行设置.

接下来,A { static A(); }运行静态构造函数.这将打印"静态A()"消息.

最后,var a = new A();执行原始语句(),但此时构造静态,以便获得最终打印.

  • A._A的构造发生在静态构造函数中.只是编译器在C#静态构造函数中声明的代码之前预先在静态构造函数(.cctor)中初始化所有字段. (2认同)
  • @prankster:我只是想说他的静态构造+初始化都是在他的非静态构造之前发生的。我改写并编辑得更清楚。 (2认同)

Hug*_*son 6

一个额外的旁注 - C# 规范(我正在查看 4.0,但它也在 3.0 中)在 10.5.5.1 静态字段初始化中说:

如果类中存在静态构造函数(第 10.12 节),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,在第一次使用该类的静态字段之前的依赖于实现的时间执行静态字段初始值设定项。

您有一个静态构造函数,因此“Otherwise”子句不适用。但是我认为如果您没有静态构造函数,则可以在“依赖于实现的时间”执行静态字段初始值设定项,这是与您的问题相关的信息。如果您的静态字段初始值设定项正在执行某种类型的数据初始化或对象创建,而无需访问静态字段本身,则这可能很重要。

我想这是深奥的,但我今天看到它发生了,因为“依赖于实现的时间”似乎在 C# 3.0 和 4.0 之间发生了变化——至少对于我所看到的情况。简单的解决方案当然很简单 - 只需添加一个静态构造函数......