静态构造函数如何工作?

om4*_*987 80 c# static-constructor c#-4.0

namespace MyNameSpace
{
    static class MyClass
    {
        static MyClass()
        {
            //Authentication process.. User needs to enter password
        }

        public static void MyMethod()
        {
            //Depends on successful completion of constructor
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass.MyMethod();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我假设的顺序

  1. 静态构造函数的开始
  2. 静态构造函数的结束
  3. 主要开始
  4. MyMethod的开始
  5. 主要结束

现在在任何情况下,如果4将在2之前开始,我被搞砸了.可能吗?

Eri*_*ert 218

你这里只问了一个问题,但是你应该问十几个问题,所以我会全部回答.

这是我假设的顺序

  1. 类构造函数的开始(也称为cctor)
  2. 结尾的
  3. 主要的开始
  4. MyMethod的开始

它是否正确?

不.正确的顺序是:

  1. 程序的启动程序,如果有的话.那没有.
  2. 程序的结尾,如果有的话.那没有.
  3. 主要开始
  4. 启动MyClass的cctor
  5. MyClass的cctor结束
  6. MyClass.MyMethod的开始

如果有静态字段初始化器怎么办?

在某些情况下,允许CLR更改静态字段初始化程序的运行顺序.有关详细信息,请参阅Jon关于该主题的页面:

静态构造函数和类型初始值设定项之间的区别

是否有可能MyMethod在该类的cctor完成之前调用静态方法?

是.如果cctor本身调用MyMethod,那么显然MyMethod将在cctor完成之前被调用.

cctor不会调用MyMethod.是否有可能MyMethod在MyClass的cctor完成之前调用静态方法?

是.如果cctor使用其cctor调用MyMethod的另一个类型,那么在MyClass cctor完成之前将调用MyMethod.

没有cctors直接或间接调用MyMethod!现在有可能MyMethod在MyClass的cctor完成之前调用静态方法吗?

没有.

即使涉及多个线程,这仍然是正确的吗?

是.在可以在任何线程上调用静态方法之前,cctor将在一个线程上完成.

可以不止一次调用cctor吗?假设两个线程都导致cctor运行.

无论涉及多少线程,都保证最多调用一次cctor.如果两个线程"同时"调用MyMethod,那么它们就会竞争.其中一个失败了比赛并阻塞,直到MyClass cctor在获胜线程上完成.

丢失的线程阻塞直到cctor完成?真的吗?

真.

那么如果获胜线程上的cctor 调用阻塞先前由丢失线程占用的锁的代码呢?

然后你有一个经典的锁定顺序反转条件.你的程序陷入僵局.永远.

这似乎很危险.我怎样才能避免死锁?

如果你这样做会伤害然后停止这样做.永远不要做可以阻止cctor的东西.

依靠cctor初始化语义来强制执行复杂的安全性要求是一个好主意吗?拥有一个用户交互的cctor是个好主意吗?

这两个都不是好主意.我的建议是,您应该找到一种不同的方法来确保满足您的方法的安全影响前提条件.

  • @phoog:我希望在使用术语方面保持一致,所以我选择了最短的术语."静态构造函数"和"类构造函数"都很好.作为一个实现细节,类型的静态构造函数作为一个名为".cctor"的特殊方法发出,因此通常将这样的构造函数称为"一个cctor".如果我在更正式的背景下写作,我会使用其中一个较长的术语. (6认同)
  • Eric,我很好奇为什么你在这个答案中用"class constructor"或"cctor"替换了"static constructor".在引用cctor时使用"静态构造函数"是不正确的吗? (5认同)
  • @Legends:*对于具有静态构造函数的非静态类也是如此吗? (2认同)

Jam*_*are 24

根据MSDN,一个静态构造函数:

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

因此,在调用静态方法之前将调用静态构造函数MyClass.MyMethod()(假设在静态构造或静态字段初始化期间不会调用).

现在,如果您正在进行异步操作static constructor,那么同步它就是您的工作.

  • 如果你正在做任何异步涉及静态构造函数中的第二个线程,*你正处于一个痛苦的世界*.没有什么比死锁更快了.有关示例,请参见http://stackoverflow.com/a/8883117/88656. (7认同)

das*_*ght 11

#3实际上是#1:静态初始化直到第一次使用它所属的类才开始.

如果MyMethod从静态构造函数或静态初始化块调用,则是可能的.如果你没有MyMethod直接或间接地从你的静态构造函数调用,你应该没问题.


ken*_*ken 9

文档(强调我的):

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