【问题标题】:Why aren't all static constructors called in C# (i.e. those of the parent classes)?为什么不是所有的静态构造函数都在 C# 中调用(即父类的构造函数)?
【发布时间】:2011-09-24 02:51:47
【问题描述】:

我有三个班级,BaseDerivedFinalDerived 派生自 BaseFinal 派生自 Derived。所有三个类都有一个静态构造函数。将Derived 类为称为Setup 的公共静态方法。当我调用Final.Setup 时,我希望所有三个静态构造函数都会执行,但只有Derived 中的一个会运行。

这里是示例源代码:

    abstract class Base
    {
        static Base()
        {
            System.Console.WriteLine ("Base");
        }
    }

    abstract class Derived : Base
    {
        static Derived()
        {
            System.Console.WriteLine ("Derived");
        }

        public static void Setup()
        {
            System.Console.WriteLine ("Setup");
        }
    }

    sealed class Final : Derived
    {
        static Final()
        {
            System.Console.WriteLine ("Final");
        }
    }

这对我来说只是部分意义。我知道调用Final.Setup() 实际上只是Derived.Setup() 的别名,所以跳过Final 中的静态构造函数似乎很公平。但是,为什么不调用Base 的静态构造函数呢?

我可以通过调用Base 的无操作静态方法或访问Base 的一些虚拟静态方法来解决此问题。但我想知道:这种明显奇怪的行为背后的原因是什么?

【问题讨论】:

标签: c# static-constructor


【解决方案1】:

在以下情况下调用静态构造函数(根据TCPL):

  • 创建了一个类类型的实例。
  • 类类型的任何静态成员都被引用。

例如,考虑一个具有静态Main 方法的类,在该类中开始执行:如果您有一个静态构造函数,它将在调用 Main 方法之前调用

请注意,即使在执行静态构造函数之前,任何静态字段都被初始化为其默认值,然后为这些字段执行静态字段初始化程序。只有这样,静态构造函数(cctor)才会被执行。


更直接地回答您的问题:静态构造函数不是继承的,也不能直接调用,因此您的 Base cctor 不会在您的场景中被调用,除非您为抽象 Base 类提供静态方法并且正如您已经建议的那样,首先调用它,即Base.Initialize()

关于推理,这很简单,考虑 C#(在 Java 中这是不同的):静态方法不被继承,因此静态构造函数也不应该被继承,因为这可能会导致不必要的副作用(当没有引用该类时调用 cctor) .

【讨论】:

  • 感谢您的澄清。这对我来说很有意义。
【解决方案2】:

静态方法属于类,没有继承。您可以调用 Final.Setup 的事实只是调用 Derived.Setup 的语法糖,因此没有引用 Final 的静态成员 - 因此不调用静态构造函数。 Base 类也一样 - 静态成员没有继承,因此 Base 类在这里不涉及任何方式。

【讨论】:

    【解决方案3】:

    C# 规则规定在创建类的第一个实例或触及任何静态成员之前调用静态构造函数,因此,可能永远不会,就像您的情况一样。

    【讨论】:

    • @phresnel:就我而言,我从不创建任何对象,只是调用Derived.Setup() 会导致静态构造函数在Derived 上运行。所以不,静态构造函数不仅在创建类的实例之前被调用。
    • @phresnel 不完全是:“在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。”从评论中的链接。这意味着如果他访问 Base 中的任何内容,它的静态构造函数就会触发。
    • @Pierre 我想我的评论回答了你的问题。你永远不会对 Base 做任何事情,因此根据上述规则,它的静态构造函数不会触发。
    • @lasseespeholt:你是对的,这也是我的结论。但是,在我看来,访问派生类中的一些静态变量相当于隐式引用基类……我仍然觉得这有点奇怪。
    • @Pierre 我倾向于同意你的观点 :) 但是,如果你真的需要这个,你必须适当地重构你的代码:/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2011-09-07
    • 2018-02-28
    • 2015-04-24
    • 2011-05-29
    • 2011-10-07
    • 2021-08-31
    相关资源
    最近更新 更多