# 原則13:使用恰當的方式對靜態成員進行初始化
**By D.S.Qiu**
**尊重他人的勞動,支持原創,轉載請注明出處:[http://dsqiu.iteye.com](http://dsqiu.iteye.com)**
你應該知道靜態成員變量在創建對象實例之前就已經初始化了。C# 提供了靜態初始化語法和靜態構造函數對靜態成員變量進行初始化。靜態構造函數是一個比其他函數,變量,屬性在沒有訪問之前就被執行的特殊函數。你可以使用這個函數初始化靜態變量,完善單例模式,或者任何需要在類還沒有被使用的必要工作。你不能使用構造函數,一些特殊 private 函數,或其他語法初始化靜態變量。
和實例初始化一樣,初始化語法是靜態構造函數的另一選擇。你只需要聲明一個靜態成員,然后使用初始化語法。如果有靜態變量的初始化邏輯很復雜,你可以創建一個靜態構造函數。
C# 實現單例模式最常用的方法就是靜態構造函數。讓構造函數變為 private ,然后添加一個初始化語法:
```
public class MySingleton
{
private static readonly MySingleton theOneAndOnly = new MySingleton();
public static MySingleton TheOnly
{
get { return theOneAndOnly; }
}
private MySingleton()
{
}
// remainder elided
}
```
單例模式很容易像上面的方式一樣實現。如果初始化邏輯更復雜:
```
public class MySingleton2
{
private static readonly MySingleton2 theOneAndOnly;
static MySingleton2()
{
theOneAndOnly = new MySingleton2();
}
public static MySingleton2 TheOnly
{
get { return theOneAndOnly; }
}
private MySingleton2()
{
}
// remainder elided
}
```
和實例初始化一樣,靜態初始化語法在任何靜態構造函數之前執行。并且,你的靜態初始化語法比基類的靜態構造函數更早執行。
CLR 在類型第一次在應用空間被訪問之前自動執行靜態構造函數。你只能定義一個靜態構造函數,并且不能有參數。因此你需要注意在靜態構造函數是否會產生異常。如果你在靜態構造函數拋出了異常, CLR 會終止你的程序。這種情況捕獲異常是非常陰險的。這時的代碼區創建這個類型就會失敗直到 AppDomain 被卸載。 CLR 就不能執行靜態構造函數去初始化這個類型。即使你再嘗試,類型不會被正確初始化。創建這個類型的對象(或者任意子類)都是沒有被定義的。所以,這是不允許的。
異常是使用靜態構造函數代替靜態初始化語法的最常見原因。因為你使用靜態初始化語法,你不能自己捕獲異常。使用靜態構造函數,你就可以(查看原則47:):
```
static MySingleton2()
{
try
{
theOneAndOnly = new MySingleton2();
}
catch
{
// Attempt recovery here.
}
}
```
靜態初始化語法和靜態構造函數是最干凈,最清晰的方式去初始化靜態成員變量。它們具有很強的可讀性和很容易正確使用。它們被支持就是為了解決這個其他語言初始化靜態成員會出現的問題。
小結:
這個事情一直拖著,一直想繼續,今天又起了個頭了,希望能一鼓作氣。翻譯很爛并且有很多不明確的地方(自己讀的疑惑),算是給自己買下一個伏筆吧,還有很多工作要去完善。
歡迎各種不爽,各種噴,寫這個純屬個人愛好,秉持”分享“之德!
有關本書的其他章節翻譯請[點擊查看](/category/297763),轉載請注明出處,尊重原創!
如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。
轉載請在**文首**注明出處:[http://dsqiu.iteye.com/blog/2077189](/blog/2077189)
更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)
- 第一章 C# 語言習慣
- 原則1:使用 屬性(Poperty)代替可直接訪問的數據成員(Data Member)
- 原則2:偏愛 readonly 而不是 const
- 原則3:選擇 is 或 as 而不是強制類型轉換
- 原則4:使用條件特性(conditional attribute)代替 #if
- 原則5:總是提供 ToString()
- 原則6:理解幾個不同相等概念的關系
- 原則7:明白 GetHashCode() 的陷阱
- 原則8:優先考慮查詢語法(query syntax)而不是循環結構
- 原則9:在你的 API 中避免轉換操作
- 原則10:使用默認參數減少函數的重載
- 原則11:理解小函數的魅力
- 第二章 .NET 資源管理
- 原則12:選擇變量初始化語法(initializer)而不是賦值語句
- 原則13:使用恰當的方式對靜態成員進行初始化
- 原則14:減少重復的初始化邏輯
- 原則15:使用 using 和 try/finally 清理資源
- 原則16:避免創建不需要的對象
- 原則17:實現標準的 Dispose 模式
- 原則17:實現標準的 Dispose 模式
- 原則18:值類型和引用類型的區別
- 原則19:確保0是值類型的一個有效狀態
- 原則20:更傾向于使用不可變原子值類型
- 第三章 用 C# 表達設計
- 原則21:限制你的類型的可見性
- 原則22:選擇定義并實現接口,而不是基類
- 原則23:理解接口方法和虛函數的區別
- 原則24:使用委托來表達回調
- 原則25:實現通知的事件模式
- 原則26:避免返回類的內部對象的引用
- 原則27:總是使你的類型可序列化
- 原則28:創建大粒度的網絡服務 APIs
- 原則29:讓接口支持協變和逆變
- 第四章 和框架一起工作
- 原則30:選擇重載而不是事件處理器
- 原則31:用 IComparable<T> 和 IComparer<T> 實現排序關系
- 原則32:避免 ICloneable
- 原則33:只有基類更新處理才使用 new 修飾符
- 原則34:避免定義在基類的方法的重寫
- 原則35:理解 PLINQ 并行算法的實現
- 原則36:理解 I/O 受限制(Bound)操作 PLINQ 的使用
- 原則37:構造并行算法的異常考量
- 第五章 雜項討論
- 原則38:理解動態(Dynamic)的利與弊
- 原則39:使用動態對泛型類型參數的運行時類型的利用
- 原則40:使用動態接收匿名類型參數