考虑这个示例代码:
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
为空。但是,更改Main
方法,如下所示:
public static void Main() {
new B();
Console.WriteLine(B.TheT);
}
正如预期的那样, B.TheT
是“测试”。我可以理解这会强制静态构造函数运行,但为什么第一种情况不会发生这种情况呢?
我尝试阅读规范,引起了我的注意(§10.12):
[...]静态构造函数的执行由第一个触发 以下事件发生在应用程序域中:
•[...]
•引用类类型的任何静态成员。
我对此的解释是,由于TheT
不是B
的成员,因此B
的静态构造函数不会被强制运行。这是对的吗?
如果这是正确的,我最好如何B
指定如何初始化TheT
?
答案 0 :(得分:5)
A.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.
}
答案 1 :(得分:0)
在第一次访问之前或最迟在第一次访问时调用静态构造函数。即,您知道在第一次访问时调用它,但不是在多久之前调用。但是,如果不进行访问,则不会调用它。因此,只有当它被调用时你才能控制它。
根据MSDN参考
静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前会自动调用它。
答案 2 :(得分:0)
在第二种情况下称为静态构造函数,它将调用实际类型的静态构造函数,而不是派生的构造函数。因此,在您的情况下,它会调用A<T> =>A<string>
的{{1}}和 的静态ctor。
要证明此行为,请执行以下操作:
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
并调用默认的静态ctor。