2010-12-22 51 views
223

請向我解釋靜態構造函數的用法。爲什麼和什麼時候我們會創建一個靜態構造函數,並且有可能重載一個?靜態構造函數的用途是什麼?

+1

應當指出的是,有建設的靜態方法(對於一個例子,仰望[Singleton設計模式(http://stackoverflow.com/questions/7095/is -the-c-sharp-static-constructor-thread-safe)),它們被用來隱藏用於實例化類的實際構造函數。這給了作者更多的關於如何使用他們的類的控制。 – Izzy 2013-04-19 10:09:29

回答

186

不,你不能重載它;靜態構造函數對於初始化與類型(或任何其他每類操作)相關的任何靜態字段非常有用 - 特別適用於將所需配置數據讀入只讀字段等。

它由運行時自動運行第一次需要它(確切的規則很複雜(參見「beforefieldinit」),並在CLR2和CLR4之間巧妙地改變)。除非你濫用反射,否則一次保證至多運行(即使兩個線程同時到達)。

+3

感謝您的回覆。你能否給我提供關於你的句子的更多細節「除非你濫用反射,它保證最多隻能運行一次」..對於靜態構造函數可以做什麼反射.. – 2010-12-22 07:27:28

+19

@Rajesh - 找到方法並調用`Invoke` 20倍。 – 2010-12-22 07:32:17

+0

嗨@MarcGravell,請說明CLR2和CLR4靜態構造函數的行爲有什麼區別。而且,這是否意味着靜態構造函數是線程安全的? – 2013-05-21 09:37:46

91

Static Constructors (C# Programming Guide)

靜態構造用於 初始化任何靜態數據,或執行 需要 僅一次執行的特定動作。在創建第一個 實例或引用任何靜態 成員之前,它將自動被稱爲 。

靜態構造函數有以下 屬性:

  • 靜態構造函數並不需要訪問修飾符或有參數。

  • 在創建第一個實例或引用任何靜態成員之前,將自動調用靜態構造函數以初始化該類。

  • 無法直接調用靜態構造函數。

  • 用戶無法控制何時在程序中執行靜態構造函數。

  • 靜態構造函數的典型用法是當類使用日誌文件並使用構造函數將條目寫入此文件時。

  • 當構造函數可以調用LoadLibrary方法時,爲非託管代碼創建包裝類時,靜態構造函數也很有用。

7

你可以使用靜態構造函數來初始化靜態字段。它在使用這些字段之前的不確定時間運行。微軟的文檔和許多開發人員警告說,類型上的靜態構造函數會帶來很大的開銷。
爲了獲得最佳性能,最好避免使用靜態構造函數。
更新:你不能在同一個類中使用一個以上的靜態構造函數,但是您可以使用其他實例構造帶(最大)一個靜態構造函數。

8

1.它只能訪問類的靜態成員。

原因:非靜態成員特定於對象實例。如果允許靜態構造函數在非靜態成員上工作,它將反映所有對象實例中的更改,這是不切實際的。

2.靜態構造函數中不應該有參數。

原因:因爲,它將被CLR調用,所以沒有人可以將參數傳遞給它。 3.只有一個靜態構造函數是允許的。

原因:重載需要兩種方法在方法/構造函數定義方面不同,這在靜態構造函數中是不可能的。

4.不應該有訪問修飾符。

理由:同樣的原因是相同的調用靜態構造函數是由CLR而不是由對象進行,無需訪問修飾符它

69

靜態構造函數也是,當你有依賴靜態字段非常有用彼此之間,使得初始化的順序很重要。如果您通過格式化程序/美化程序運行代碼來更改字段的順序,那麼您可能會發現自己的空值不在您希望的位置。

例:假設我們有這個類:

class ScopeMonitor 
{ 
    static string urlFragment = "foo/bar"; 
    static string firstPart= "http://www.example.com/"; 
    static string fullUrl= firstPart + urlFragment; 
} 

當您訪問fullUr,這將是 「http://www.example.com/foo/bar」。

幾個月後,你正在清理你的代碼,並字段字段(假設他們是一個更大的列表的一部分,所以你沒有注意到這個問題)。你:現在

class ScopeMonitor 
{ 
    static string firstPart= "http://www.example.com/"; 
    static string fullUrl= firstPart + urlFragment; 
    static string urlFragment = "foo/bar"; 
} 

fullUrl值就是「http://www.example.com/」,因爲urlFragment尚未在fullUrl正在設定的時間進行初始化。不好。因此,您可以添加靜態構造函數取初始化的護理:

class ScopeMonitor 
{ 
    static string firstPart= "http://www.example.com/"; 
    static string fullUrl; 
    static string urlFragment = "foo/bar"; 

    static ScopeMonitor() 
    { 
     fullUrl= firstPart + urlFragment; 

    } 
} 

現在,無論你有什麼樣的順序領域,初始化永遠是正確的。

1

靜態構造函數

構造函數聲明使用static修飾符是一個靜態構造函數。靜態構造函數用於初始化靜態數據或執行需要在類的生命週期中僅執行一次的特定操作。靜態構造函數是在類中執行的第一個代碼塊。靜態構造函數在類的生命週期中只執行一次。它被自動調用。靜態構造函數不接受任何參數。它沒有訪問說明符。它不直接調用。

3

爲什麼和什麼時候我們會創建一個靜態構造函數...?

其中一個特定使用靜態構造函數的原因是創建一個'超級枚舉'類。這裏有一個(簡單的,做作)例如:

public class Animals 
{ 
    private readonly string _description; 
    private readonly string _speciesBinomialName; 

    public string Description { get { return _description; } } 
    public string SpeciesBinomialName { get { return _speciesBinomialName; } } 

    private Animals(string description, string speciesBinomialName) 
    { 
     _description = description; 
     _speciesBinomialName = speciesBinomialName; 
    } 

    private static readonly Animals _dog; 
    private static readonly Animals _cat; 
    private static readonly Animals _boaConstrictor; 

    public static Animals Dog { get { return _dog; } } 
    public static Animals Cat { get { return _cat; } } 
    public static Animals BoaConstrictor { get { return _boaConstrictor; } } 

    static Animals() 
    { 
     _dog = new Animals("Man's best friend", "Canis familiaris"); 
     _cat = new Animals("Small, typically furry, killer", "Felis catus"); 
     _boaConstrictor = new Animals("Large, heavy-bodied snake", "Boa constrictor"); 
    } 
} 

你會使用它非常相似(在句法外觀)任何其他枚舉:

Animals.Dog 

這比普通enum的優點是,您可以輕鬆封裝相關信息。一個缺點是你不能在switch語句中使用這些值(因爲它需要不變的值)。

相關問題