C#规范读取
触发了针对结构类型的静态构造函数的执行在应用程序中发生以下第一个事件域:
- 引用了结构类型的静态成员。
- 被显式声明的struct类型的构造函数被调用。
在下面的代码中,尽管没有发生上述事件,但仍调用了静态构造函数。
struct Notebook
{
static Notebook() => Console.WriteLine("Static Ctor");
public void Method() => Console.WriteLine("Method");
}
class Program
{
static void Main()
{
Notebook notebook;
notebook.Method();
}
}
当在结构体中声明的自动属性在void Main()中分配了一个值时,这同样适用。在这种情况下,实际上是什么使静态构造函数被调用?
在我看来,这种差异从根本上说是C# language specification(最新的非草稿规范,即C#5.0,已链接,但其他版本在这方面本质上是相同的)之间的冲突。
具体来说,语言规范提供了您提到的触发器,但是CLI规范中包括了对标记有the Common Language Infrastructure specification标志的类型not的描述(如此处所示):
何时以及什么触发此类类型初始化方法的执行的语义如下:…4.如果未标记为BeforeFieldInit,则该类型的初始化方法将在处执行(即,被触发):一种。首次访问该类型的任何静态字段,或者b。首次调用该类型的任何静态方法,或者c。如果是值,则首次调用该类型的任何实例或虚拟方法类型或d。首次调用该类型的任何构造函数。
(我的重点)
换句话说,对于运行时,规则明确地是,调用任何类型的实例方法将导致静态构造函数(即“ type initializer”)被调用。这就是您的程序的行为方式。
C#规范中的语言持续了很长时间,从规范的早期版本一直到该语言的最新发行版本(从技术上讲是“草稿”规范,但仍然是规定性的),我很难想到这种差异是一个简单的疏忽。当然,[[可能是(禁止语言设计者的输入)。但是我认为尽管CLI规则,语言设计者还是决定对限制进行最小限度的限制(从理论上讲,C#语言可以针对其他类似的平台,可能不像CLI那样受限制)。与众不同。
毕竟,遵循C#程序的规则而不是C#规则的CLI实现对于任何人都不太可能出现问题。当程序本身不访问任何静态成员的方法被调用时,实际上不调用静态构造函数的程序应该是非常罕见的,并且可以说是非常糟糕的设计。