静态构造函数在实例构造函数之后调用?

Vla*_*lad 17 c# static constructor

亲爱的,这个问题已经被问过了,但在答案中,没有解释我所看到的问题.

问题:C#编程指南说:

静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作.在创建第一个实例或引用任何静态成员之前自动调用它.

特别是,在创建类的任何实例之前调用静态构造函数.(这不能确保静态构造函数在创建实例之前完成,但这是另一回事.)

我们来看一下示例代码:

using System;

public class Test
{
    static public Test test = new Test();
    static Test()
    {
        Console.WriteLine("static Test()");
    }
    public Test()
    {
        Console.WriteLine("new Test()");
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Main() started");
        Console.WriteLine("Test.test = " + Test.test);
        Console.WriteLine("Main() finished");
    }
}
Run Code Online (Sandbox Code Playgroud)

它输出:

Main()启动
新的Test()
static Test()
Test.test = Test
Main()完成

因此,我们可以看到实例构造函数在静态构造函数启动之前完成(因此创建了一个实例).这不符合指南吗?也许静态字段的初始化被认为是静态构造函数的隐式部分?

SLa*_*aks 26

static字段的内联初始值设定项在显式static构造函数之前运行.

编译器将您的类转换为以下内容:

public class Test {
    .cctor {    //Class constructor
        Test.test = new Test();                //Inline field initializer
        Console.WriteLine("static Test()");    //Explicit static ctor
    }
    .ctor { ... }    //Instance constructor
}
Run Code Online (Sandbox Code Playgroud)

请注意,这与声明顺序无关.

引用规范:

类的静态字段变量初始值设定项对应于以它们出现在类声明中的文本顺序执行的赋值序列.如果类中存在静态构造函数(第10.11节),则在执行该静态构造函数之前立即执行静态字段初始值设定项.

  • @Vlad:C#将字段初始值设定项和静态构造函数视为两个独立的概念.但是,.NET只有一个:*type initializer*,它带有特殊名称`.cctor`.C#编译器将字段初始值设定项和静态构造函数放入类的.NET*类型初始值设定项*中..NET保证*类型初始化程序*在任何实例构造函数之前开始运行,并且在您的示例中也是如此.当C#规范试图将它分成两个概念时,它就会变得不一致.实际行为受CLR规范的约束. (4认同)