如何触发静态构造函数
本文关键字:构造函数 静态 何触发 | 更新日期: 2023-09-27 18:04:18
代码:
class Base<T,U> where T:Base<T,U>,new() where U :class
{
protected static U _val = null;
internal static void ShowValue()
{
if(_val == null)new T(); //Without this line, it won't work as expected
Console.WriteLine (_val);
}
internal static void Virtual()
{
Console.WriteLine ("Base");
}
}
class Deriv :Base<Deriv,string>
{
static Deriv()
{
_val = "some string value";
}
internal static new void Virtual ()
{
Console.WriteLine ("Deriv");
}
}
public static void Main (string[] args)
{
Deriv.ShowValue();
Deriv.Virtual();
}
多亏了.NET的泛型,我可以创建一堆特定的类,重用泛型基类中定义的泛型静态方法。它可以在一定程度上模仿遗传多态性。但是为了初始化不同版本的静态字段,我必须使用静态构造函数。不幸的是,我们不能直接调用它们,因此,我们必须想办法触发它的调用。上面给出的例子说明了一种方法。但我既不喜欢实例化,也不喜欢反射方法。我们也不能对泛型参数的静态方法进行约束。所以,我想问一下,是否有其他方法可以做这种工作!
事先谢谢!
~~~~~~
一些结论(可能有点早(:
似乎没有解决这种情况的办法。我必须实例化一个子类或使用反射。考虑到.cctor只需要调用一次,我赞成反射方法,因为在某些情况下,new((约束不是一种选择,就像你不应该向用户公开无参数的ctor一样。
经过进一步的实验,我发现.cctors可能会被多次调用,但只有第一次调用才会影响静态字段的设置。这很奇怪,但很奇怪!
class MyClass
{
static int _val = 0;
static MyClass()
{
_val++;
Console.WriteLine (_val);
}
}
public static void Main (string[] args)
{
ConstructorInfo ci = typeof(MyClass).TypeInitializer;
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
ci.Invoke(new object[0]);
}
//result:
//1
//1
//1
//1
我强烈建议您重新考虑您的设计。尝试使用这种"静态继承"的变通方法是为了对抗.NET.的一些核心设计
目前还不清楚你想解决什么更大的问题,但尝试像这样的"聪明"代码来模拟继承会导致代码很难长期维护和诊断。
如果没有实际使用Deriv
的成员(或创建它的实例(,基本上就不会触发静态构造函数。重要的是要理解Deriv.ShowValue()
基本上被转换为对的调用
Base<Deriv, string>.ShowValue();
所以你实际上并不是在Deriv
上调用任何东西。如果是这样写的话,您的调用代码实际上会更清晰。
EDIT:避免显式使用类型初始值设定项的另一个(显然是不幸的(原因是.NET 4.5中有一个错误,在某些情况下会导致不适当地抛出异常。有关更多信息,请参阅我的问题。
正确的解决方案是调用类型初始值设定项(=静态构造函数(,如下所示:
typeof(T).TypeInitializer.Invoke(null, null);
它需要两个null
。只指定一个会得到MemberAccessException
。
因此,您的代码可能希望看起来像这样:
internal static void ShowValue()
{
if (_val == null)
{
if (typeof(T).TypeInitializer != null)
typeof(T).TypeInitializer.Invoke(null, null);
if (_val == null)
throw new InvalidOperationException(string.Format("The type initializer of {0} did not initialize the _val field.", typeof(T)));
}
Console.WriteLine(_val);
}
这样,就可以删除new()
约束。
您无法控制静态构造函数何时执行,但可以保证的是,它将在访问任何静态属性或方法之前以及实例化之前运行。
确实没有理由希望静态构造函数在较早的时候执行。如果您没有使用类中的任何内容,但希望运行静态构造函数中的代码,那么您的设计中就出现了问题。
静态构造函数是自动的,只有一次。你不能自己叫他们。
这里的一个例子:
public class Bus
{
// Static constructor:
static Bus()
{
System.Console.WriteLine("The static constructor invoked.");
}
public static void Drive()
{
System.Console.WriteLine("The Drive method invoked.");
}
}
class TestBus
{
static void Main()
{
Bus.Drive();
}
}
输出:
The static constructor invoked.
The Drive method invoked.
我引导您阅读MSDN上关于静态构造函数的文章,并在页面下方搜索大约10%:
会自动调用静态构造函数来初始化类在创建第一个实例或任何静态成员之前引用。