How to trigger a static constructor

左心房为你撑大大i 提交于 2019-12-04 07:39:56
Jon Skeet

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.

You have no control of when the static constuctor will execute, but what is guaranteed is that it will run before accessing any static property or method and before instantiation.

There is really no reason to want the static constructor to execute at an earlier point. If you are not using anything from the class but you want the code in the static constructor to run, then something is wrong in your design.

The correct solution is to invoke the type initializer (= static constructor) like this:

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

It needs both nulls. Specifying only one gives a MemberAccessException.

Thus, your code might want to look something like this:

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

And with that, you can remove the new() constraint.

Static constructors are automatically, only once. You cannot call them yourself.

An example from here:

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

output:

The static constructor invoked.

The Drive method invoked.

I direct you to the MSDN article on Static Constructors and about 10% down the page:

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!