2010-07-01 296 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()); 
    } 
} 

現在,當您再次運行同樣的事情,它的工作原理...