我有一个定义为:
的类public class DatabaseEntity<T> where T : DatabaseEntity<T> {
public static string Query { get; protected set; }
public static IList<T> Load() {
return Database.Get(Query);
}
}
public class Node : DatabaseEntity<Node> {
static Node() {
Node.Query = @"SELECT Id FROM Node";
}
}
当我从代码隐藏(Node.Load()
)运行Window.xaml.cs
时,Node的静态构造函数永远不会触发;或者至少没有遇到断点,也没有将Node.Query设置为null以外的任何东西。
有什么理由可能会发生这种情况吗?
解决方案
请查看以下答案,了解一些解决方案。对于我的情况,我决定公开Query
变量,并在一个地方设置Query
的所有实例。 (不理想,但它有效。)
答案 0 :(得分:4)
是的,在首次访问类的成员或创建第一个实例之前,不会调用静态构造函数。
在您的情况下,您正在访问DatabaseEntity<T>.Load
,因此将调用DatabaseEntity<T>
的静态构造函数而不是其派生类。
即使您调用Node.Load
,它也会在编译时映射到DatabaseEntity<Node>
。从技术上讲,你根本不会访问Node
课程。
答案 1 :(得分:4)
问题在于您对何时调用静态构造函数的假设。 documentation表示
,它不是最清楚的在创建第一个实例或引用任何静态成员之前自动调用它。
如果你打电话
,你可能会认为Node.Load();
您正在Node
类上调用静态方法,但实际上您正在基类上调用它,因为这是实现它的地方。
所以,要解决这个问题,你有两个选择。首先,您可以通过在调用Load()
之前创建Node类的新实例来显式触发静态构造函数
var foo = new Node(); // static ctor triggered
Node.Load();
或者创建一个受保护的虚拟成员,基类可以调用以获取查询值(不幸的是,这里不能使用抽象)
public class DatabaseEntity<T> where T : Derp {
protected abstract string Query { get; }
public static IList<T> Load() {
return Database.Get(new DatabaseEntity<T>().Query);
}
}
两者都是hacky。最好完全放弃静态并使用实例方法。应谨慎使用静力学,因为它们会导致紧耦合和其他设计难题。
答案 2 :(得分:0)
您还可以通过执行以下操作直接使用System.Runtime.CompilerServices
和RuntimeHelpers
类型调用类构造函数:
RuntimeHelpers.RunClassConstructor(type.TypeHandle);
例如,您可以使用反射在继承链中循环所有类型并调用每个静态构造函数。