静态构造函数如何工作?

时间:2012-02-22 16:10:17

标签: c# c#-4.0 static-constructor

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

这是我假设的序列

  1. 静态构造函数的开始
  2. 静态构造函数的结束
  3. 主要开始
  4. MyMethod的开始
  5. 主要结束
  6. 现在在任何情况下,如果4将在2之前开始我被搞砸了。有可能吗?

10 个答案:

答案 0 :(得分:217)

你这里只问过一个问题,但是你应该提出的问题有十几个问题,所以我会全部回答。

  

这是我假设的序列

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

    这是对的吗?

    没有。正确的顺序是:

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

      如果有静态字段初始值设定项怎么办?

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

      The differences between static constructors and type initializers

        

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

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

        

      cctor不会调用MyMethod。在MyClass的cctor完成之前,是否有可能调用像MyMethod这样的静态方法?

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

        

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

      没有

        

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

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

        

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

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

        

      丢失的线程阻止直到cctor完成?

      真。

        

      那么,如果中止线程上的cctor调用阻塞丢失线程之前锁定的代码,该怎么办?

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

        

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

      如果你这样做会伤害,那么停止这样做永远不要做可以阻止cctor的事情。

        

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

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

答案 1 :(得分:23)

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

  

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

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

现在,如果您在static constructor中执行任何异步操作,那么同步它就是您的工作。

答案 2 :(得分:11)

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

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

答案 3 :(得分:9)

来自documentation(强调我的):

  

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

答案 4 :(得分:2)

你可以保证4总是在2之后(如果你没有用静态方法创建你的类的实例),但对于1和3则不一样。

答案 5 :(得分:2)

在执行mymethod之前将调用静态构造函数。但是如果你被搞砸了,如果在2之前调用4,那么我建议你重新思考你的设计。无论如何,不​​应该在静态构造函数中做复杂的事情。

答案 6 :(得分:2)

CLR保证静态构造函数在访问任何静态成员之前运行。但是,你的设计有点臭。做这样的事情会更直接:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

根据您的设计,如果身份验证失败,阻止MyMethod运行的唯一方法是抛出异常。

答案 7 :(得分:2)

确保在执行任何方法之前调用静态类的构造函数。例如:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

输出:

  

按Enter键

     输入后

//

     

嗨来了......

     

你好!

     

你好!

答案 8 :(得分:1)

以下是事情发生的实际顺序:

  1. Main
  2. 的开头
  3. 开始静态MyClass构造函数
  4. 静态MyClass构造函数
  5. 的结尾
  6. MyMethod
  7. 的开头
  8. Main
  9. 结束

答案 9 :(得分:0)

或者您可以在调试器中单步执行。