靜態建構函式

2021-04-21 22:52:52 字數 3433 閱讀 2189

1、如果乙個類沒有定義靜態建構函式,就算它有靜態字段,編譯器也不會自動給這個類生成乙個預設的靜態建構函式。

驗證如下:

using system;

using system.collections.generic;

using system.text;

namespace teststaticconstructor

static

void main()        

",b.y);  

console.readline();}} 

}我們來看反編譯之後的il語言:

.class

private auto ansi beforefieldinit b

extends [mscorlib]system.object

.method private hidebysig static

void main() cil managed

"l_0006: ldsfld int32 teststaticconstructor.b::y

l_000b: box int32

l_0010: call void [mscorlib]system.console::writeline(string, object)

l_0015: nop 

l_0016: call string [mscorlib]system.console::readline()

l_001b: pop 

l_001c: ret 

}.field public

static int32 y

}上面的il語言中,自動幫b這個類生成了預設的建構函式,但並沒有自動生成靜態建構函式,就算它有靜態字段。

2、靜態建構函式、初始化語句,哪個先執行呢?實際上是初始化語句先執行,之後如果是第一次訪問該類,而且該類有靜態建構函式的話,才會去訪問靜態建構函式,而且只訪問這一次。

看下面的**:

using system;

using system.collections.generic;

using system.text;

namespace teststaticconstructor

static

void main()        

",b.y);

console.readline();}} 

}上面**的執行結果是y=2,而不是y=1,說明是先執行初始化語句

public

static

int y = 1;再進入靜態建構函式的。而且我們如果設定斷點進行跟蹤的話,也確實是這個順序。如何證明靜態建構函式只進過一次呢?可以設定計數器來測試一下,這裡就不試了。

另外大家來觀察下上面**反編譯為il後的**:

.class

private auto ansi b

extends [mscorlib]system.object

.method public hidebysig specialname rtspecialname instance void .ctor() cil managed

.method private hidebysig static

void main() cil managed

"l_0006: ldsfld int32 teststaticconstructor.b::y

l_000b: box int32

l_0010: call void [mscorlib]system.console::writeline(string, object)

l_0015: nop 

l_0016: call string [mscorlib]system.console::readline()

l_001b: pop 

l_001c: ret 

}.field public

static int32 y}

大家可以發現有兩個建構函式,但這兩個建構函式的名字不一樣,靜態建構函式的名字變成了cctor(),跟ctor()區別開了,這應該是編譯器做的地下工作。

3、類的靜態建構函式在給定應用程式域中至多執行一次:

只有第一次建立類的例項或者引用類的任何靜態成員(注意是成員,並不僅僅是靜態字段)才激發靜態建構函式被呼叫。

觀察下面**的執行結果即知道不僅僅是靜態欄位能引發靜態建構函式:

using system;

using system.collections.generic;

using system.text;

namespace teststaticconstructor

public

static

void test() 

}class b

",b.y);

a.test();

console.readline();}} 

}執行結果:

y = 0

in a()

in test()

說明呼叫a的test()靜態方法時也觸發了a類的靜態建構函式。

4、如果有兩個類,a類和b類,這兩個類都有靜態建構函式,而且這兩個類彼此之間有依賴關係,那又會怎麼樣呢?

比如下面這段**:

using system;

class a

}class b

static

void main()         

, y = ", a.x, b.y);

console.readline();}}

執行的結果是:

static a()

static b()

x = 1,y = 2

為什麼會是這樣呢?我們按順序來走一下:

b類有main(),所以下到b類這裡,先執行b類的初始化語句

public

static

int y = a.x + 1;呼叫到了a.x,這時候編譯器認識到此時a類還沒有被呼叫過,就被打發去執行a類的初始化語句,接著執行a類的靜態建構函式,在a類的靜態建構函式裡發現要呼叫b類的y,即b.y,可能編譯器在這裡發現了再這樣跑下去就死鎖了,就執行了某種操作,直接把b.y當0返回給a了,於是算出a.x = 0 + 1 = 1,接著把a的靜態建構函式跑完,再返回到y = a.x + 1,算出b.y =  2,接著就執行b類的靜態建構函式。

在programming c#中文版的第四版82頁下面的注5裡,寫了一段話,現引用過來:

(注5:實際上,clr保證在類的其他操作之前執行靜態構造方法。但是,它只保證啟動靜態構造方法,實際上不保證它的執行結束。因此,可以人為地製造出一種病態情況,兩個類互相具有迴圈依賴關係。這時,clr會在不同的執行緒中執行構造方法,以兌現至少以正確的順序啟動兩個構造方法的最低保證,不會出現死鎖。

)從上面的測試中,我們已經知道至少類的靜態變數的初始化語句會在靜態建構函式之前執行,所以注5的第一句就是有問題的。至於下面說的對不對,我還不知道怎麼去考證。

靜態建構函式

1 靜態建構函式既沒有訪問修飾符,也沒有引數。因為是.net呼叫的,所以像public和private等修飾符就沒有意義了。2 是在建立第乙個類例項或任何靜態成員被引用時,net將自動呼叫靜態建構函式來初始化類,也就是說我們無法直接呼叫靜態建構函式,也就無法控制什麼時候執行靜態建構函式了。3 乙個類...

靜態建構函式

1.類的建構函式有三種 例項建構函式,私有建構函式和靜態建構函式,靜態建構函式只能初始化靜態資料,或執行一次特殊的操作,這種函式只執行一次,在第一次建立類的物件的時候或者呼叫靜態成員時就會自動呼叫它,靜態建構函式沒有訪問修飾符,也沒有任何引數。可以參考一下下面的 using system using...

靜態建構函式

先看一道常見題目,以下 的執行結果是什麼?classa class b 一 定義 由名稱可知,靜態建構函式 也稱為型別建構函式 包含 靜態 和 建構函式 兩個特點。第乙個特點決定了它與靜態函式類似,只能使用靜態成員 第二個特點決定了它與建構函式類似,具有初始化作用,並且沒有返回值。與建構函式 針對例...