如何触发静态构造函数

Nee*_*eed 6 c# static-constructor

码:

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();
}
Run Code Online (Sandbox Code Playgroud)

由于.NET的泛型,我可以创建一堆特定的类,重用通用基类中定义的泛型静态方法.它可以在一定程度上模仿继承多态性.但是为了初始化不同版本的静态字段,我要使用静态构造函数.不幸的是,我们无法直接调用它们,因此,我们必须找到一种方法来触发它的调用.上面给出的例子显示了一种方法.但我不喜欢实例化或反射方法.我们也不能对泛型参数的静态方法进行约束.所以,我想问一下,如果还有其他办法可以做这种工作!

先谢谢!

~~~~~~~~~~~~~~~~

一些结论(也许有点早):

似乎没有解决方法来处理这种情况.我必须实例化一个子类或使用反射.考虑到.cctors只需要调用一次,我赞成反射方法,因为在某些情况下,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
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

我强烈建议你重新考虑你的设计.尝试将这种解决方法用于"静态继承"是针对.NET的一些核心设计.

目前还不清楚你要解决的是什么更大的问题,但尝试这样的"聪明"代码来模拟继承会导致代码在较长时期内难以维护和诊断.

如果没有实际使用Deriv(或创建它的实例)的成员,您基本上不会触发静态构造函数.重要的是要了解Deriv.ShowValue()基本上转换为调用

Base<Deriv, string>.ShowValue();
Run Code Online (Sandbox Code Playgroud)

......所以你实际上并没有打电话Deriv.如果以这种方式编写,您的调用代码实际上会更清晰.

编辑:另一个(显然不幸)明确避免使用类型初始化程序的原因是.NET 4.5中存在一个错误,导致在某些情况下不正确地抛出异常.有关详细信息,请参阅有关该主题的问题.

  • @Timwi:鉴于OP*正在与.NET的核心设计作斗争,重新思考设计对我来说似乎仍然是个好建议.希望存在静态虚拟成员并不能使它们可用,并且您的设计应该基于您*可以*做的而不是您想要做的*. (3认同)
  • @Timwi:我没有移动球门柱.如果你必须明确地调用类型初始化器,你显然*正在与.NET的设计作斗争.每当您必须使用变通方法因为您的设计未在类型系统中满足时,您应该尝试重新设计.如果不了解更多个人情况,就不可能提供替代设计 - 我怀疑由于我不知道的限制,我建议的任何东西都会被击落. (2认同)

Chr*_*ens 0

静态构造函数是自动的,仅一次。你不能自己打电话给他们。

这里的一个例子:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

The static constructor invoked.

The Drive method invoked.
Run Code Online (Sandbox Code Playgroud)