6

代码:

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 的泛型,我可以使用泛型基类中定义的泛型静态方法创建一堆特定的类。它可以在一定程度上模仿继承多态性。但是为了初始化不同版本的静态字段,我必须使用静态构造函数。不幸的是,我们不能直接调用它们,因此,我们必须想办法触发它的调用。上面给出的示例显示了一种方法。但我不喜欢实例化或反射方法。我们也不能对泛型参数的静态方法进行约束。所以,我想问一下,是否还有其他方法可以完成这种工作!

预先感谢!

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

一些结论(可能有点早):

似乎没有解决方法来处理这种情况。我必须实例化一个子类或使用反射。考虑到 .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
4

5 回答 5

6

我强烈建议您重新考虑您的设计。尝试将这种解决方法用于“静态继承”正在与 .NET 的一些核心设计作斗争。

目前尚不清楚您要解决什么更大的问题,但是尝试像这样的“聪明”代码来模拟继承将导致代码在长期内很难维护和诊断。

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

Base<Deriv, string>.ShowValue();

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

编辑:避免显式使用类型初始值设定项的另一个(显然是不幸的)原因是 .NET 4.5 中存在一个错误,该错误会导致在某些情况下不恰当地抛出异常。有关更多信息,请参阅我关于该主题的问题。

于 2011-08-02T06:30:50.553 回答
3

正确的解决方案是像这样调用类型初始化程序(=静态构造函数):

typeof(T).TypeInitializer.Invoke(null, null);

它需要两个nulls。仅指定一个会给出一个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()约束。

于 2012-11-16T14:39:04.920 回答
2

您无法控制静态构造函数何时执行,但可以保证它会在访问任何静态属性或方法之前以及在实例化之前运行。

确实没有理由希望静态构造函数在更早的时候执行。如果您没有使用类中的任何内容,但您希望静态构造函数中的代码运行,那么您的设计中有问题。

于 2011-08-02T06:21:19.790 回答
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();
    }
}

输出:

The static constructor invoked.

The Drive method invoked.
于 2011-08-02T06:19:06.180 回答
0

我将您定向到有关静态构造函数的 MSDN 文章以及页面下方约 10% 的位置:

在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。

于 2011-08-02T06:22:29.893 回答