在引用任何静态成员之前调用静态构造函数
Static constructor is called before any static members are referenced
根据文档:
A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced.
但我在 Whosebug post 中看到了 C# 规范中的以下引用:
If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor.
自相矛盾,我不明白什么在先,静态构造函数还是静态成员初始化。
考虑这个 class:
public static class TestStatic
{
public static int SomeValue = GetValue();
static TestStatic()
{
Console.WriteLine("Constructor");
}
}
还有这个配套方法:
public static int GetValue()
{
Console.WriteLine("GetValue");
return 5;
}
如果您 运行 此代码:
Console.WriteLine(TestStatic.SomeValue);
您将得到的输出是:
GetValue
Constructor
5
所以你可以看到你发布的两个陈述都是正确的。在引用静态成员(SomeValue
)之前调用构造函数,在构造函数之前调用静态字段初始化程序。
这种行为的原因(这是设计使然)是静态字段的初始化实际上是作为静态构造函数的一部分发生的。编译器在静态构造函数逻辑前面加上静态字段初始值设定项的所有表达式。
你所提到的两个说法都是正确的,并且是相互同步的。我不确定你为什么认为它们是矛盾的。
执行顺序如下:
- Static fields with initializers.
- Static Constructor.
以上是根据你的第二个陈述。第一条语句仅提及执行这些操作的时间,即之前:
- The first instance of the class is created.
- Any static members are referenced.
实际上,上述条件可以作为静态构造函数的保证,即静态字段初始值设定项将被执行,静态构造函数将在两者中的任何一个发生之前被调用(语句 1)。
C# specification 明确提到:
The static constructor for a class executes at most once in a given
application domain. The execution of a static constructor is triggered
by the first of the following events to occur within an application
domain: An instance of the class is created. Any of the static members
of the class are referenced. If a class contains the Main method
(Section 3.1) in which execution begins, the static constructor for
that class executes before the Main method is called. If a class
contains any static fields with initializers, those initializers are
executed in textual order immediately prior to executing the static
constructor.
只是补充一下,因为你已经突出显示 -
before the first instance is created or any static members are referenced.
这只是意味着可以在创建 class 的实例之前引用 class 的静态成员。因此,即使在那种情况下,静态构造函数也会在访问静态成员之前被调用。
如果你在他的回答中看到 DavidG 的代码,即使 class 没有被实例化,但是其中一个静态成员被引用,静态字段初始化仍然发生在后面的静态构造函数执行。
示例:
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.");
}
}
现在如果你执行:
Console.WriteLine(Test.i);
您得到以下输出:
Static field initializer called.
Static Constructor called.
10
根据文档:
A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced.
但我在 Whosebug post 中看到了 C# 规范中的以下引用:
If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor.
自相矛盾,我不明白什么在先,静态构造函数还是静态成员初始化。
考虑这个 class:
public static class TestStatic
{
public static int SomeValue = GetValue();
static TestStatic()
{
Console.WriteLine("Constructor");
}
}
还有这个配套方法:
public static int GetValue()
{
Console.WriteLine("GetValue");
return 5;
}
如果您 运行 此代码:
Console.WriteLine(TestStatic.SomeValue);
您将得到的输出是:
GetValue
Constructor
5
所以你可以看到你发布的两个陈述都是正确的。在引用静态成员(SomeValue
)之前调用构造函数,在构造函数之前调用静态字段初始化程序。
这种行为的原因(这是设计使然)是静态字段的初始化实际上是作为静态构造函数的一部分发生的。编译器在静态构造函数逻辑前面加上静态字段初始值设定项的所有表达式。
你所提到的两个说法都是正确的,并且是相互同步的。我不确定你为什么认为它们是矛盾的。
执行顺序如下:
- Static fields with initializers.
- Static Constructor.
以上是根据你的第二个陈述。第一条语句仅提及执行这些操作的时间,即之前:
- The first instance of the class is created.
- Any static members are referenced.
实际上,上述条件可以作为静态构造函数的保证,即静态字段初始值设定项将被执行,静态构造函数将在两者中的任何一个发生之前被调用(语句 1)。
C# specification 明确提到:
The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain: An instance of the class is created. Any of the static members of the class are referenced. If a class contains the Main method (Section 3.1) in which execution begins, the static constructor for that class executes before the Main method is called. If a class contains any static fields with initializers, those initializers are executed in textual order immediately prior to executing the static constructor.
只是补充一下,因为你已经突出显示 -
before the first instance is created or any static members are referenced.
这只是意味着可以在创建 class 的实例之前引用 class 的静态成员。因此,即使在那种情况下,静态构造函数也会在访问静态成员之前被调用。
如果你在他的回答中看到 DavidG 的代码,即使 class 没有被实例化,但是其中一个静态成员被引用,静态字段初始化仍然发生在后面的静态构造函数执行。
示例:
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.");
}
}
现在如果你执行:
Console.WriteLine(Test.i);
您得到以下输出:
Static field initializer called.
Static Constructor called.
10