2014-09-30 93 views
4

這兩個代碼塊是否做同樣的事情?這兩個構造函數都做同樣的事情嗎?

class A { 
    public static int s; 
    A(){} 
    static A(){s = 100;} 
} 

class A { 
    public static int s=100; 
    A(){} 
    //static A(){s = 100;} do not use 
} 

他們做同樣的事情?我想是這樣。

+0

's'的兩個實例都是100,是的。 – Matthew 2014-09-30 16:34:24

+0

在這種情況下,他們會在事實後產生相同的結果,他們會以不同的方式做到這一點。 – David 2014-09-30 16:36:44

+0

請嘗試使用搜索並分享您找到的內容。之前所有的答案都已經解釋過了。請參閱http://stackoverflow.com/questions/8285168/why-static-fields-initialization-occurs-before-the-static-constructor,http://stackoverflow.com/questions/2761393/static-readonly-field-initializer -vs-static-constructor-initialization – CodeCaster 2014-09-30 16:40:13

回答

11

不,他們的表現不盡相同。如果沒有靜態構造函數,類型初始化程序執行的時間就會更加鬆散 - 它可能比您期望的更早發生或更高版本

當存在一個靜態構造函數時,類型初始化程序在第一次使用類型時根據被訪問的靜態成員或任何正在創建的實例執行。

不是是一個靜態構造函數時,唯一的保證是初始化程序將在第一次訪問靜態字段之前的某個點執行(並且仍然只是一次)。根據JIT,這可能意味着它很早就執行(例如,當您首次執行可能會使用的成員)或非常遲(之後調用不使用任何字段的靜態成員,或在創建並使用實例)。

在IL中,區別在於沒有靜態構造函數的類型具有beforefieldinit標誌;一個靜態構造函數不包含。

+0

當兩個選項都可能的時候,你通常喜歡哪一個,有沒有靜態構造函數定義? – 2014-10-02 14:12:18

+0

@LucaCremonesi:通常我會選擇哪一個更清楚 - 這通常是*沒有靜態構造函數,除非我在初始化中進行了大量工作(通常這是一種設計異味)。 – 2014-10-02 14:17:37

4

效果是一樣的,但執行的實際順序可能不同。當存在靜態構造函數時,靜態字段會在調用構造函數之前立即進行初始化,或者訪問任何靜態字段。如果沒有靜態構造函數,則可以在第一次使用其中一個靜態字段之前的任何時間執行字段初始值設定項

由於您的初始化有沒有副作用,不能拋出異常,也不會有兩個任何明顯的差別,禁止使用反射或其他一些旁觀者(如調試器)

+0

不完全:當存在一個靜態構造函數時,它在構造函數被調用之前或任何靜態成員。當沒有靜態構造函數時,它在任何對* static *字段的訪問之前 - 使用實例字段不必觸發初始化程序。 – 2014-09-30 16:41:58

+1

@JonSkeet謝謝 - 更新 – 2014-09-30 16:43:04

3

的除了一些邊緣例如beforefieldinit行爲,是的,他們做同樣的事情。事實上,編譯後的IL在兩種情況下幾乎相同。唯一的區別是在沒有靜態構造函數的情況下存在beforefieldinit

class A 
{ 
    public static int s; 
    A() { } 
    static A() { s = 100; } 
} 

class B 
{ 
    public static int s = 100; 
    B() { } 
} 

編譯爲...

.class private auto ansi A 
    extends [mscorlib]System.Object 

.class private auto ansi beforefieldinit B 
    extends [mscorlib]System.Object 

具有相同方法/字段定義。

0

根據C#果殼靜態構造函數,當你第一次使用的財產,並在此大多數使用的是當你要計算或讀取一些數據,並設置爲靜態屬性(像執行來自appconfig.config的密碼)。如果不使用靜態構造函數,則必須定義Init方法,並在應用程序啓動時調用它。

相關問題