潜在的隐患与静态构造函数在C#静态、隐患、函数

由网友(心针)分享简介:我的问题来重构仅包含静态方法声明为一个静态类,并启动应用程序时遇到了奇怪的问题,一下课。My question comes after refactoring a class that contained only static methods to be declared as a static class, an...

我的问题来重构仅包含静态方法声明为一个静态类,并启动应用程序时遇到了奇怪的问题,一下课。

My question comes after refactoring a class that contained only static methods to be declared as a static class, and experiencing weird issues when starting the application.

我还没有进行任何深入的调查,但是似乎正在取得一些呼叫从静态构造函数中未完成的某些原因。

I have not performed any thorough investigation but it seems that some call being made from within the static constructor does not complete for some reason.

所以,我想知道哪里有使用静态构造函数在C#中,当有任何陷阱?更具体地,是否有应不惜一切代价避免和无法从静态构造内使用?任何事

So, I would like to know where there are any pitfalls when using static constructors in C#? More specifically, are there any things that should be avoided at all cost and not be used from within the static constructor?

推荐答案

有几个陷阱,以静态构造函数。例如,如果一个静态构造函数抛出一个异常,你将继续得到一个 TypeInitializationException 每当你访问它的任何成员。

There are several pitfalls to static constructors. For example, if a static constructor throws an exception, you would continue getting a TypeInitializationException whenever you access any of its members.

如果静态构造函数抛出一个异常,运行时就不会调用它第二次,并且类型将保持未初始化的在你的程序正在运行的应用程序域的生命周期。

If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.

在一般情况下,静态类应该只在无状态的情况下,您将不再需要任何初始化中使用。如果你的类需要进行初始化,您可能会更好使用 Singleton模式,它可以是lazily初始化第一次访问:

In general, static classes should only be used in stateless scenarios where you won’t need any initialization. If your class needs to be initialized, you might be better off using the singleton pattern, which can be lazily initialized on first access:

public class MyClass
{
    private static readonly Lazy<MyClass> current = 
        new Lazy<MyClass>(() => new MyClass());

    public static MyClass Current
    {
        get { return current.Value; }
    }

    private MyClass()
    {
        // Initialization goes here.
    }

    public void Foo()
    {
        // ...
    }

    public void Bar()
    {
        // ...
    }
}

static void Main(string[] args)
{
    MyClass.Current.Foo();   // Initialization only performed here.
    MyClass.Current.Bar();
    MyClass.Current.Foo();
}

修改:我做了一些进一步阅读了就不管了,并且看起来静态构造函数的执行的原因死锁如果执行阻塞操作(例如,异步回调或线程同步)在其中。

Edit: I did some further reading up on the matter, and it appears that static constructors do cause deadlocks if you perform blocking operations (e.g. asynchronous callbacks or thread synchronization) within them.

在CLR内部使用被执行多次,同时锁定于prevent型初始化(静态构造函数)。因此,如果你的静态构造函数试图访问它从另一个线程声明类型的另一名成员,这将不可避免地发生死锁。由于其他部件可能被宣布为PLINQ或TPL操作的一部分,一个匿名函数,这些错误可能是微妙的,难以辨认。

The CLR internally uses locking to prevent type initializers (static constructors) from being executed multiple times concurrently. Thus, if your static constructor attempts to access another member of its declaring type from another thread, it would inevitably deadlock. Since "another member" could be an anonymous function declared as part of a PLINQ or TPL operation, these bugs can be subtle and hard to identify.

伊戈尔·奥斯特洛夫斯基(MSFT)解释了这个在他的静态构造函数死锁的文章,提供了一个僵局的下面的例子:

Igor Ostrovsky (MSFT) explains this in his Static constructor deadlocks article, providing the following example of a deadlock:

using System.Threading;

class MyClass
{
    static void Main() { /* Won’t run... the static constructor deadlocks */  }

    static MyClass()
    {
        Thread thread = new Thread(arg => { });
        thread.Start();
        thread.Join();
    }
}

在上面的例子中,新的线程需要访问空匿名功能, {} ,系统定义为它的回调。然而,由于匿名函数被编译为 MyClass的幕后的另一个私有方法,新线程不能在 MyClass的类型初始化。而且,因为 MyClass的静态构造函数需要等待新的线程来完成第一(因为的Thread.join()),死锁随之而来。

In the above example, the new thread needs to access the empty anonymous function, { }, defined as its callback. However, since the anonymous function is compiled as another private method of MyClass behind the scenes, the new thread cannot access it before the MyClass type initializes. And, since the MyClass static constructor needs to wait for the new thread to complete first (because of thread.Join()), a deadlock ensues.