【问题标题】:Why the static constructor in a struct gets called when calling a non-static method?为什么在调用非静态方法时会调用结构中的静态构造函数?
【发布时间】:2020-01-27 20:43:39
【问题描述】:

C#规范是这样写的

触发结构类型的静态构造函数的执行 由以下事件中的第一个在应用程序中发生 域名:

  • 引用了结构类型的静态成员。
  • 结构类型的显式声明的构造函数被调用。

在以下代码中,尽管没有发生上述事件,但仍调用了静态构造函数。

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() 中赋值时,同样适用。 在这种情况下,究竟是什么让静态构造函数被调用?

【问题讨论】:

  • 来自here在创建第一个实例或引用任何静态成员之前自动调用[A static constructor]。
  • @RobertHarvey 另一方面lang spec:structs:“结构类型的默认值(Default values)的创建不会触发静态构造函数。(这方面的一个例子是元素的初始值)数组。)”看起来需要挖掘出最新的非草案规范并仔细阅读它以确认.Method是实际触发它的那个(即使它不是static)......可能就是这种情况没有注释说“方法不调用静态方法”)
  • @Alexei:C# 5 规范(之所以选择是因为我碰巧有它)与上面提到的文本基本相同。我发现这种行为与 OP 一样令人费解,因为我的理解是,如果没有“.beforefieldinit”,运行时应该完全按照规范执行构造函数(包括静态的,并包括在结构中)。只有使用该标志(此处不存在)才允许运行时“过早”调用静态构造函数。然而,这里似乎确实如此。即使在非草案规范中,我也没有看到任何理由。
  • 还有它的价值:至少早在 2010 年,Stack Overflow 上就已经注意到了这种行为:Why doesn't the CLR always call value type constructors。这个问题实际上问的是相反的问题——为什么 不是 调用的静态构造函数。但是接受的答案确实讨论了这样一个事实,即如果调用任何方法,静态构造函数将首先被调用(即按照@Alexei 之前的建议)。

标签: c# struct constructor static


【解决方案1】:

在我看来,这种差异基本上是 C# language specification(最新的非草案规范,即 C# 5.0,已链接,但其他版本在这方面基本相同)和 the Common Language Infrastructure specification 之间的冲突。

具体来说,语言规范给出了您提到的触发器,但 CLI 规范包括对标有 BeforeFieldInit 标志的类型的描述(就像这里的情况一样):

何时以及什么触发此类初始化方法的执行的语义如下:

4. 如果没有标记 BeforeFieldInit 则该类型的初始化方法在 (i.e., 被触发):
一种。首次访问该类型的任何静态字段,或
湾。首次调用该类型的任何静态方法,或
c。如果它是一个值,则首次调用该类型的任何实例或虚拟方法 输入
d。首次调用该类型的任何构造函数。

(我的重点)

换句话说,对于运行时,规则明确地表明调用任何类型的实例方法都会导致调用静态构造函数(即“类型初始化器”)。这正是您的程序的行为方式。

C#规范中的语言已经存在了这么久,从早期版本的规范一直到最新发布的语言版本(技术上是“草案”规范,但仍然是规定性的),我很难想象这种差异是一个简单的疏忽。它可能当然是(除非语言设计者的输入)。但我认为,尽管 CLI 的规则,语言设计者决定尽量减少限制(因为理论上,C# 语言可以针对其他类似的平台,可能不像 CLI 那样限制的平台),而且只是活出与众不同。

毕竟,C# 程序的 CLI 实现遵循其规则而不是 C# 规则,对任何人来说都不太可能有问题。当一个不访问静态成员的方法本身被调用时,程序实际上依赖不被调用的静态构造函数应该是非常罕见的,并且可以说是非常糟糕的设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 2010-11-29
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    相关资源
    最近更新 更多