在引用任何静态成员之前调用静态构造函数

T.S*_*T.S 4 c# static-constructor

根据文档:

\n\n
\n

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

\n
\n\n

但我在 stackoverflow 帖子中看到了以下来自 C# 规范的引用:

\n\n
\n

如果类中存在静态构造函数 (\xc2\xa710.12),则在执行该静态构造函数之前立即执行静态字段初始值设定项。

\n
\n\n

这是矛盾的,我不明白静态构造函数和静态成员初始化哪个先出现。

\n

Dav*_*idG 5

考虑这个类:

public static class TestStatic
{
    public static int SomeValue = GetValue();

    static TestStatic()
    {
        Console.WriteLine("Constructor");
    }

}
Run Code Online (Sandbox Code Playgroud)

还有这个支撑方法:

public static int GetValue()
{
    Console.WriteLine("GetValue");
    return 5;
}
Run Code Online (Sandbox Code Playgroud)

如果您运行此代码:

Console.WriteLine(TestStatic.SomeValue);
Run Code Online (Sandbox Code Playgroud)

您将得到的输出是:

GetValue
Constructor
5
Run Code Online (Sandbox Code Playgroud)

所以你可以看到你发布的两种说法都是正确的。在引用静态成员 ( SomeValue) 之前调用构造函数,并且在构造函数之前调用静态字段初始化程序。


Sha*_*ngh 5

你提到的两种说法都是真实的并且相互吻合。我不确定你为什么认为它们是矛盾的。

执行顺序如下:

  1. 带有初始值设定项的静态字段。
  2. 静态构造函数。

以上是根据你的第二个陈述。第一条语句仅提到执行这些操作的时间,即之前:

  1. 创建该类的第一个实例。
  2. 任何静态成员都会被引用。

事实上,上述条件可以视为静态构造函数的保证,即在两者中的任何一个发生之前,将执行静态字段初始值设定项并调用静态构造函数(语句 1)。

C #规范明确提到:

类的静态构造函数在给定的应用程序域中最多执行一次。静态构造函数的执行由应用程序域中发生的以下第一个事件触发: 创建类的实例。类的任何静态成员都会被引用。如果一个类包含开始执行的 Main 方法(第 3.1 节),则该类的静态构造函数将在调用 Main 方法之前执行。如果类包含任何带有初始值设定项的静态字段,则这些初始值设定项将在执行静态构造函数之前立即按文本顺序执行。

只是补充一下,因为您已经强调了 -

在创建第一个实例或引用任何静态成员之前。

这仅意味着即使在创建类的实例之前也可以引用该类的静态成员。因此,即使在这种情况下,静态构造函数也会在访问静态成员之前被调用。

如果您在 DavidG 的回答中看到代码,即使该类没有被实例化,但静态成员之一被引用,静态字段初始化仍然发生在静态构造函数执行之前。

例子:

public static class Test
{
    public static int i = 10;
    public static int j = new Func<int>(() => { 
            Console.WriteLine("Static field initializer called."); return 20; 
        })();
    static Test()
    {
        Console.WriteLine("Static Constructor called.");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在如果你执行:

Console.WriteLine(Test.i);
Run Code Online (Sandbox Code Playgroud)

您将得到以下输出:

调用静态字段初始值设定项。

静态构造函数被调用。

10