2009-12-21 65 views
3

何時分配靜態變量,即何時聲明類或創建對象時?.net中的靜態變量分配時間

+0

請參閱此相關的問題:http://stackoverflow.com/questions/218461/difference-initializing-static-variable-inline-or-in-static-constructor-in-c – 2009-12-21 15:31:59

回答

6

它被編譯成靜態構造函數。因此,當任何人第一次創建該類的對象或調用靜態方法或屬性時,就會進行初始化。

編輯:如果初始化發生在自己的靜態構造函數代碼之前(以及其他一些邊界情況),當它對你很重要時,請通過divo檢查註釋中的鏈接。

+6

它不那麼簡單。 Jon Skeet有關於此的綜合性文章,請參閱http://www.yoda.arachsys.com/csharp/beforefieldinit.html。在沒有靜態構造函數的類中,類型初始值設定項可能會在程序集被加載時執行,或者當該類型的靜態方法被執行,或者甚至只有當類型的第一個字段被訪問時纔會運行。 – 2009-12-21 15:29:56

+0

這是一個非常有趣的鏈接,divo。謝謝。我認爲在大多數實際的目的中,我的答案是可以的,但似乎比我想象的要多。 – 2009-12-21 15:35:39

+0

是的,正如Jon所寫的:「很多類實際上並不需要許多C#程序員所承擔的行爲 - 實際上,大多數人不需要知道其中的差異。」但它可能正是這些邊緣案例引發的意外錯誤。 – 2009-12-21 15:40:05

4

首次類被訪問....

+1

雖然你的回答是「足夠好」它可以更好。 – ChaosPandion 2009-12-21 15:19:00

0

只要調用static(type)構造函數就會分配靜態變量。當您在方法執行之前調用任何第一次引用類型的方法時,會發生這種情況。

+0

只有*是*靜態類型的構造函數時纔是如此。 – 2009-12-21 15:35:18

+0

任何顯式字段初始化都將在構造函數體之前編譯到構造函數中。如果沒有聲明的靜態構造函數,編譯器會生成一個。 – ironic 2009-12-21 15:52:15

+0

@ironic:不,情況並非如此。如果沒有靜態構造函數,該類將被標記爲'beforefieldinit'標誌,這意味着執行類型初始化程序的時間不確定。 – 2009-12-21 16:03:33

2

正如其他答案已經表明,這將發生在類型(靜態)構造函數。如果你的類沒有明確定義的類型構造函數,那麼編譯器會爲你生成一個類型構造函數。但是,確定何時調用該構造函數的確切時間有點多。

如果您的類未定義顯式類型構造函數,例如

public class Foo 
{ 
    public static int Bar = 1; 
} 

然後C#編譯器將生成一個構造函數並使用beforefieldinit標誌發出類定義。這將導致JIT編譯器保證類型構造函數在第一次使用該類型的成員之前被調用,但這次是非確定性的,即不可能確切地知道何時會發生這種情況,並且它可能在比首次使用類型成員時要早得多。

如果你的類聲明瞭一個顯式的類型構造函數,例如

public class Foo 
{ 
    public static int Bar; 
    static Foo() 
    { 
     Bar = 1; 
    } 
} 

然後編譯器會發出IL而沒有beforefieldinit標誌。在這種情況下,JIT編譯器將在確定的時間調用類型構造器,即緊接在第一類型成員訪問之前。

前者JIT行爲稱爲前場-INIT語義和後者作爲精確 sematntics。瞭解兩者之間的差異很重要,因爲在某些情況下,它們可能會有重大的性能影響。

+0

nitpick:對於'beforefieldinit'而言,重要的是靜態構造函數是否存在,而不是*你的字段是否在構造函數中初始化。如果類沒有靜態構造函數,那麼它將被編譯器標記爲'beforefieldinit';如果該類有一個靜態構造函數,那麼它將不會被標記爲'beforefieldinit',而不管它的字段被初始化的位置。 – LukeH 2009-12-21 15:51:19

+0

仍然這應該是被接受的答案:-) – 2009-12-21 15:52:26

+0

@Luke - 感謝指出。 Nitpicking是好的;-)已編輯 – 2009-12-22 07:17:03