C 靜態建構函式(型別構造器)的要點

2021-07-30 18:02:30 字數 3004 閱讀 1263

在c#中 型別構造器(type constructor),也稱為靜態構造器(static constructor)、類構造器(class constructor)、型別初始化器(type initializer)。型別構造器可應用於介面(目前c#編譯器不支援)、引用型別和值型別。例項構造器的作用是設定型別的例項初始狀態。型別構造器的作用是設定型別的初始狀態。型別預設沒有定義構造器,如果定義只能定義乙個。此外型別構造器永遠沒有引數,而且必須標記為static,總是私有的。c#編譯器會自動把它們標記為private.如果在源**只能怪顯示將型別構造器標記為private或者其它訪問修飾符。c#編譯就會丟擲error.之所以私有,是為了阻止任何由開發人員寫的**呼叫,對型別構造器的呼叫總是由clr負責的。

雖然值型別可以定義乙個型別構造器,但最好不要這麼做,因為clr不一定去呼叫型別構造器,如下例子

namespace

nowcoderprogrammingproject

}class

testsomevaltype}}

型別構造器的效能

在編譯乙個方法時,jit編譯器要決定是否在方法中生成乙個對型別構造器的呼叫。如果jit編譯器決定生成這個呼叫,它還必須決定將這個呼叫新增到什麼位置。具體什麼位置,有以下兩種可能:

jit編譯器可以剛好在建立型別的第乙個例項前,或者剛好在訪問類的乙個非繼承的字段或成員之前生成這個呼叫。這稱為」精確」(precise)語義,因為clr呼叫型別構造器的時機拿捏恰到好處。

jit編譯器可能在首次訪問乙個靜態欄位或乙個靜態/例項方法之前,或者在呼叫乙個例項構造器之前,隨便找個時間生成。這稱為」字段初始化前」(before-field-init)語義,因為clr只保證訪問成員之前會執行型別構造器,可能提前很早就允許了。  

using system;

using system.collections.generic;

using system.diagnostics;

using system.linq;

using system.text;

using system.threading.tasks;

namespace nowcoderprogrammingproject

public

class userprecise

}class testbeforefieldinit

private

static

void

test1(int32 iterations)

sw.stop();

console.writeline("test1-userbeforefieldinit 用時:" + sw.elapsedmilliseconds);

sw = stopwatch.startnew();

for (int32 j = 0; j < iterations; j++)

sw.stop();

console.writeline("test1-userprecise 用時:" + sw.elapsedmilliseconds);

}private

static

void

test2(int32 iterations)

sw.stop();

console.writeline("test2-userbeforefieldinit 用時:" + sw.elapsedmilliseconds);

sw = stopwatch.startnew();

for (int32 j = 0; j < iterations; j++)

sw.stop();

console.writeline("test2-userprecise 用時:" + sw.elapsedmilliseconds);}}

}

輸出結果為:

我們看下對應的il原始碼:

c#編譯器如果看到乙個類(beforefieldinit)包含進行了內聯初始化的靜態字段,會在類的型別定義表中生成乙個新增了beforefiledinit元資料標記的記錄項。c#編譯器如果看到乙個類包含顯示的型別構造器,就不會新增beforefiledinit元資料標記。靜態字段只要在訪問之前初始化就可以了,具體什麼時間無所謂。而顯式型別構造器可能包含具有***的**,所以需要在精確拿捏執行的時間從輸出結果來看,這個決定對效能影響很大。當test1執行第乙個迴圈時需要的時間為3411(根據不同的機器執行結果不同),第二個迴圈為5072.而二個迴圈裡面的時間非常接近,因為jit編譯器知道型別的構造器已被呼叫,所以本地**不需要包含任何對型別構造器方法的呼叫。

遺憾的是目前c#還不允許在源**中設定beforefieldinit標誌,而是讓c#編譯器根據型別構造器隱士還是顯式建立來決定是否設定這個值。

所以我們最後根據需要慎重選擇靜態構造器

參考《clr via c# 第四版》

C 建構函式靜態建構函式的區別

建構函式和靜態建構函式在乙個類中是可以共存的。靜態建構函式的執行在建構函式之前,當類第一次被code用到的時候執行,而建構函式一定是要例項化物件的時候才執行。測試 using system statica public int high 100 public string name jarry cl...

C 構造器(建構函式)

定義和作用 構造器是在構建類的 引用時 自動執行的方法。所以,每個類都必須至少要有乙個構造器。在訪問乙個類的時候,編譯器最先執行構造器中的 它與類同名,帶引數的構造器能夠獲取引數,但是與方法不同的是 構造器雖然也是一種 例項型別 即必須通過例項來進行呼叫,也可以稱之為引用型別 但是卻不能返回任何值 ...

C 靜態建構函式

c 靜態建構函式 靜態建構函式是 c 的乙個新特性,在程式設計過程中用處並不廣,它的主要目的是用於初始化一些靜態的變數。因為這個建構函式是屬於類的,而不屬於任何乙個例項,所以這個建構函式只會被執行一次,而且是在建立此類的第乙個例項或引用任何靜態成員之前,由 net 自動呼叫。在程式中我們可以這樣寫 ...