2010-07-01 123 views
5

如果我们的项目中还有一个静态类,那么哪个静态类首先初始化?哪个静态类首先初始化?

例如:下面的代码给出了null异常。

class Program 
    { 
     static void Main(string[] args) 
     { 
      First.Write(); 
      Second.Write(); 
     } 
    } 
    static class First 
    { 
     public static int[] firstArray = new int[20]; 
     public static int[] secondArray = Second.secondArray; 
     public static void Write() 
     { 
      Console.WriteLine(firstArray.ToString()); 
      Console.WriteLine(secondArray.ToString()); 
     } 
    } 
    static class Second 
    { 
     public static int[] firstArray = First.firstArray; 
     public static int[] secondArray = new int[30]; 
     public static void Write() 
     { 
      Console.WriteLine(firstArray.ToString()); 
      Console.WriteLine(secondArray.ToString()); 
     } 
    } 

如果你留意,你会看到,如果First类将初始化自己这样的SecondsecondArray领域将是空的。但是,如果Second类将首先初始化,那么SecondfirstArray将为空。我想告诉哪个初始化会产生不同的结果。

我认为这是关于我的项目的抽象问题。我在试图理解为什么会得到意想不到的结果时遇到它。

回答

10

First将开始初始化,分配firstArray,然后注意它需要初始化Second以获得初始值secondArray

Second将开始初始化,然后注意到它需要首先初始化。但是,CLR会注意到,第一个是已经在当前线程中初始化,所以它不会被阻塞。 Second的初始化将完成,然后First的初始化将完成。

幸运的是,Second需要的字段已被分配,所以发生了“正确的事情”。

这一切都很好,如果First实际上开始初始化。然而,因为这两个类都没有静态构造函数,所以有可能Second会先开始初始化...然后它会开始初始化First,这会发现Second已经初始化并且取Second.secondArray的当前值(null)为First.secondArray。这将是一件坏事。请注意,没有静态构造函数的类型的初始化时间具有changed in .NET 4 - 不是以破坏性的方式,而可能是以破坏现有代码的方式。

如果同时FirstSecond有静态构造函数,然后First将首先初始化,因为这是第一类Main接触。

道德答案:不要这样做。相互引用的类型初始化器非常容易出错。又如,见Eric Lippert和Neal Gafter的NDC 2010演讲,“C#Puzzlers”,可在NDC video page上查看。

+0

是否标准保证这个命令?我的猜测是,每个类在第一次访问之前初始化为一些未定义的类,这会将其变为随机解决的依赖性循环。 – 2010-07-01 11:28:16

+0

@Tim:我已经更新了我的答案 - 没有静态构造函数,顺序确实是未定义的。 – 2010-07-01 11:28:48

+0

随着调试器附加到VS2005,一件坏事发生 - 'Second.firstArray'被设置为'null' – AakashM 2010-07-01 11:29:56

0

我不相信对于初始化哪种静态类型有任何保证。为了确保字段初始化正确的使用方法,你需要添加静态构造函数,例如:

static class Second 
{ 
    public static int[] firstArray = First.firstArray; 
    public static int[] secondArray = new int[30]; 

    static Second() { } 

    public static void Write() 
    { 
     Console.WriteLine(firstArray.ToString()); 
     Console.WriteLine(secondArray.ToString()); 
    } 
} 

现在,当您再次运行同样的事情,它的工作原理...