C# 中静态构造函数的文档说:
静态构造函数用于 初始化任何静态数据,或者 执行需要的特定操作 仅执行一次。它被称为 自动 在第一个之前 创建实例或任何静态 成员被引用.
最后一部分(关于何时自动调用)让我大吃一惊;在阅读那部分之前,我认为通过简单地访问一个类以任何方式,我可以确定它的基类的静态构造函数已被调用。测试和检查文档表明情况并非如此;似乎在访问该基类的成员之前,基类的静态构造函数不能保证运行。
现在,我想在大多数情况下,当您处理派生类时,您将构造一个实例,这将构成正在创建的基类的实例,因此将调用静态构造函数。但如果我只处理衍生 类的 static 成员,那又怎样呢?
为了使这一点更加具体,我认为下面的代码可以工作:
abstract class TypeBase
{
static TypeBase()
{
Type<int>.Name = "int";
Type<long>.Name = "long";
Type<double>.Name = "double";
}
}
class Type<T> : TypeBase
{
public static string Name { get; internal set; }
}
class Program
{
Console.WriteLine(Type<int>.Name);
}
我假设访问 Type<T>
类会自动调用
TypeBase
的静态构造函数;但事实似乎并非如此。
Type<int>.Name
是
null
,上面的代码输出空字符串。除了创建一些虚拟成员(例如不执行任何操作的静态
Initialize()
方法)之外,是否有更好的方法来确保在使用其任何派生类型之前调用基类型的静态构造函数? 如果不是,那么...就是虚拟会员!
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof (TypeBase).TypeHandle);
您可以在派生类的静态构造函数中调用它。
除了“如果这样做会伤害你,就不要这样做”之外,我对你没有任何建议。我只是想指出,相反的情况也可能会咬你:
class Program
{
static void Main(string[] args)
{
D.M();
}
}
class B
{
static B() { Console.WriteLine("B"); }
public static void M() {}
}
class D: B
{
static D() { Console.WriteLine("D"); }
}
尽管已经调用了“D 的成员”,但仍打印“B”。 M 仅通过继承成为 D 的成员; CLR 无法区分 B.M 是“通过 D”调用还是“通过 B”调用。
非常复杂,在 CLR 2.0 和 CLR 4.0 之间,它们实际上以微妙而有趣的方式发生了变化,IMO 使得大多数“聪明”的方法在 CLR 版本之间变得脆弱。如果 Initialize()
方法also 不涉及字段,则它可能无法在 CLR 4.0 中完成这项工作。 我会寻找替代设计,或者可能在您的类型中使用
regular延迟初始化(即检查一点或参考(针对null
)以查看是否已完成)。
class Base
{
static Base()
{
Console.WriteLine("Base static constructor called.");
}
internal static void Initialize() { }
}
class Derived : Base
{
static Derived()
{
Initialize(); //Removing this will cause the Base static constructor not to be executed.
Console.WriteLine("Derived static constructor called.");
}
public static void DoStaticStuff()
{
Console.WriteLine("Doing static stuff.");
}
}
class Program
{
static void Main(string[] args)
{
Derived.DoStaticStuff();
}
}
另一个选项是在派生类型中包含一个静态只读成员,该成员执行以下操作:
private static readonly Base myBase = new Base();
因此,您的方法略有不同。这是更多的代码,但它允许您稍后定义自定义类型,以便您执行自定义操作。
abstract class TypeBase
{
private static bool _initialized;
protected static void Initialize()
{
if (!_initialized)
{
Type<int>.Instance = new Type<int> {Name = "int"};
Type<long>.Instance = new Type<long> {Name = "long"};
Type<double>.Instance = new Type<double> {Name = "double"};
_initialized = true;
}
}
}
class Type<T> : TypeBase
{
private static Type<T> _instance;
public static Type<T> Instance
{
get
{
Initialize();
return _instance;
}
internal set { _instance = value; }
}
public string Name { get; internal set; }
}
然后,当您向 Type 添加虚拟方法并想要 Type 的特殊实现时,您可以这样实现:
class TypeInt : Type<int>
{
public override string Foo()
{
return "Int Fooooo";
}
}
然后通过更改将其连接起来
protected static void Initialize()
{
if (!_initialized)
{
Type<int>.Instance = new TypeInt {Name = "int"};
Type<long>.Instance = new Type<long> {Name = "long"};
Type<double>.Instance = new Type<double> {Name = "double"};
_initialized = true;
}
}
我的建议是避免使用静态构造函数 - 这很容易做到。还要避免静态类和静态成员(如果可能)。我并不是说永远不会,只是说要谨慎。更喜欢类的单例而不是静态类。
abstract class TypeBase
{
static TypeBase()
{
Type<int>.Name = "int";
Type<long>.Name = "long";
Type<double>.Name = "double";
}
}
class Type<T> : TypeBase
{
static Type()
{
new Type<object>();
}
public static string Name { get; internal set; }
}
class Program
{
Console.WriteLine(Type<int>.Name);
}