继承的静态成员的静态初始化

6

考虑这个示例代码:

public class A<T> 
{
    public static T TheT { get; set; }
}
public class B : A<string>
{
    static B() {
        TheT = "Test";
    }
}

public class Program {
    public static void Main(String[] args) {
        Console.WriteLine(B.TheT);
    }
}

这里的B.TheT是null。然而,将Main方法更改为以下内容:

public static void Main() {
    new B();
    Console.WriteLine(B.TheT);
}

TheT是“Test”,这是预期的结果。我可以理解这会强制运行静态构造函数,但为什么第一种情况不会发生呢?

我尝试阅读规范,并注意到以下内容(§10.12):

[...] 静态构造函数的执行由应用程序域中发生的以下事件中的第一个触发:

• [...]

• 引用类类型的任何静态成员。

我的理解是,由于TheT不是B的成员,因此不会强制运行B的静态构造函数。这正确吗?

如果是这样的话,我该如何最好地让B指定如何初始化TheT


1
顺便说一下,如果您没有通过泛型重载名称“A”,那么您的示例将更加清晰。 - Jon Skeet
@JonSkeet:好主意。我会给它换个名字(在实际使用中作为一种速记方式有点合理,但在这里可能会有点混淆)。 - carlpett
3个回答

5

A. "Test"是"TheT"的缩写,这是预期的。我可以理解这会强制静态构造函数运行,但为什么第一个情况不会发生呢?

基本上,你并没有真正引用B。如果你查看IL代码,我认为你会发现你的代码实际上等价于:

public static void Main(String[] args) {
    Console.WriteLine(A<string>.TheT);
}

编译器已经确定了你指的是那个成员变量,即使你写的是B.TheT。
如果这是正确的,我该如何最好地让A指定如何初始化TheT?
说实话,我会尽量避免这样做...但你可以向B添加一个静态方法:
public static void Initialize() {
    // Type initializer will be executed now.
}

ه½“ه£°وکژن¸؛public class B : A<int> { static B() { TheT = 5; } }و—¶ï¼Œوƒ…ه†µهڈکه¾—و›´هٹ وœ‰è¶£م€‚ - L.B
@DavidPfeffer:这里没有猜测 - 它知道 A : A<string> - Jon Skeet
2
@carlpett:不,我不知道有什么简单的方法来做到这一点,坦白地说,像这样使用静态初始化通常在我看来是设计上的问题。 - Jon Skeet
@fsimonazzi:我已经在示例代码中更改了名称,请参见问题的注释。 - carlpett
@JonSkeet:可能这是一个糟糕的设计,是的。我应该另外发一篇问题相关的文章,而不是在评论中讨论。感谢澄清! - carlpett
显示剩余4条评论

0
在第二种情况下,称为静态构造函数,它将调用实际类型的静态构造函数,而不是派生的静态构造函数。因此,在您的情况下,它调用 A<T> =>A<string> 的静态构造函数,而不是 A 的静态构造函数。
要证明这种行为,请执行以下操作:
public class Base {

    static Base() {
      "Base static".Dump(); 
    }
}

public class Derived : Base {

    static Derived() {
      "Derived static".Dump(); 
    }

    public static string temp = "Hello";
}

并调用

Derived.temp.Dump();

你将会得到:

Derived static
Hello

这是你在代码中实际执行的操作,你访问派生类型A<string>并调用它的默认静态构造函数。


0

静态构造函数在第一次访问之前或最迟在第一次访问时被调用。也就是说,当第一次访问时,您知道它已经被调用,但不知道多久之前被调用。但是,如果没有访问,它将不会被调用。因此,您无法控制何时调用,只能控制是否调用。

根据MSDN的参考

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接