如何触发静态构造函数 [英] How to trigger a static constructor

查看:307
本文介绍了如何触发静态构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码:

  Base类< T,U>其中T:基地< T,U>,新的()其中U:类
{
受保护的静态û_val = NULL;
内部静态无效ShowValue()
{
如果(_val == NULL)新T(); //如果没有这一行,它不会如预期
Console.WriteLine(_val)工作;
}
内部静态无效的虚拟()
{
Console.WriteLine(基地);
}
}
类DERIV:基< DERIV,串>
{
静态DERIV()
{
_val =一些字符串值;
}
内部静态无效的新虚拟()
{
Console.WriteLine(DERIV);
}
}
公共静态无效的主要(字串[] args)
{
Deriv.ShowValue();
Deriv.Virtual();
}



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



由于事先!



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



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



这似乎是没有解决方法来处理这种情况。我必须实例化一个子类,或者使用反射。考虑到.cctors只需要调用一次,我赞成反射的办法,因为在一些情况下,一个新的()约束仅仅是不是一种选择 - 就像你不应该暴露参数的构造函数用户。



进行进一步的实验中,我发现,在.cctors可以被称为多次,但只在第一次调用会影响静态字段的设置。这是奇怪的,但良好的怪事

  MyClass类
{
静态INT _val!= 0;
静态MyClass的()
{
_val ++;
Console.WriteLine(_val);
}
}
公共静态无效的主要(字串[] args)
{
ConstructorInfo CI = typeof运算(MyClass的).TypeInitializer;
ci.Invoke(新对象[0]);
ci.Invoke(新对象[0]);
ci.Invoke(新对象[0]);
}
//结果是:
// 1
// 1
// 1
// 1


解决方案

我会强烈建议你重新考虑你的设计。尝试使用这种解决方法静态遗产的战斗是对一些.NET的核心设计的。



目前还不清楚你想要什么解决更大的问题,而是试图聪明这样的代码来模拟继承会导致代码,这是非常难以维护,并在长期的诊断。



如果没有的实际上的使用 DERIV (或创建它的一个实例)的成员,基本上你的不会的触发静态构造函数。要了解这一点很重要 Deriv.ShowValue()基本上转化为呼叫

 基地< DERIV,串> .ShowValue(); 



...所以你没有的真正的呼吁任何 DERIV 。你的调用代码实际上是清晰的,如果写这样



编辑:另外一个(显然不幸的)理由,以避免使用类型初始化明确的是,有一个错误的.NET 4.5这导致异常在某些情况下不适当被抛出。请参见的话题我的问题的详细信息。


code:

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();
}

Thanks to the generics of .NET, I can create a bunch of specific classes reusing generic static methods defined in the generic base class. It can mimic inheritance polymorphism to some extent. But in order to initialize different version of static fields, I've to use static constructors. Unfortunately, we can't call them directly, therefore, we have to figure out a way to trigger it's invocation. The example given above showed a way. But I don't like either the instantiation,or the reflection approach. We also can't make a constraint on a static method of a generic parameter. So, I'd like to ask, if there is another way to do this kind of job!

Thanks beforehand!

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

Some Conclusion (Maybe a little early):

It seems there is no workaround to deal with this kind of situation. I have to instantiate a subclass or use reflection. Considering the .cctors need merely be called once, I'm in favor of the reflection approach, because in some case, a new() constraint is just not a choice - like you're not supposed to expose the parameterless ctor to user.

After conducting further experiment, I find out that the .cctors may be called multi-times but only the first invocation will affect the setting of static fields. That's weird, but a good weirdness!

    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

解决方案

I would strongly advise you to rethink your design. Attempting to use this sort of workaround for "static inheritance" is fighting against some of the core designs of .NET.

It's unclear what bigger problem you're trying to solve, but trying "clever" code like this to simulate inheritance will lead to code which is very hard to maintain and diagnose in the longer term.

Without actually using a member of Deriv (or creating an instance of it), you basically won't trigger the static constructor. It's important to understand that Deriv.ShowValue() is basically converted into a call to

Base<Deriv, string>.ShowValue();

... so you're not actually calling anything on Deriv. Your calling code would actually be clearer if it were written that way.

EDIT: One other (clearly unfortunate) reason to avoid using type initializers explicitly is that there's a bug in .NET 4.5 which causes an exception to be thrown inappropriately in some cases. See my question on the topic for more information.

这篇关于如何触发静态构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆