首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 靜態建構函數深度解析:特性、執行時機與七大注意事項

     編輯:關於C語言

什麼是靜態建構函數?

**靜態建構函數** 是屬於**類別本身**而非實例的特殊方法,用於**初始化靜態欄位/屬性**或執行**類別級別的一次性設定**(如註冊依賴、載入原生庫、設定靜態快取)。

語法特徵

public class MyClass
{
    // 靜態建構函數:無存取修飾詞、無參數、名稱與類別同名、前綴 static
    static MyClass()
    {
        // 初始化靜態成員
        StaticField = ComputeInitialValue();
        NativeLibrary.Load("mylib.dll");
    }

    public static int StaticField { get; private set; }
}

七大核心規則與注意事項

#規則說明與範例
1無存取修飾詞、無參數由 CLR 自動呼叫,不需 `public`/`private`;無法手動呼叫,故無參數。
2自動觸發時機在**建立第一個實例** 或 **存取任意靜態成員** 之前,由 CLR 保證執行一次。時機非精確可控(受 JIT、型別初始化優化影響)。
3每個類別僅能有一個重複定義會編譯錯誤。
4可與無參數實例建構函數共存雖然簽章相同(無參數),但一個屬於型別、一個屬於實例,CLR 依上下文區分,不衝突。
5生命週期中至多執行一次即使多線程同時觸發,CLR 保證線程安全、僅執行一次(內部有鎖機制)。
6不可被繼承子類別有自己的靜態建構函數;父類別的靜態建構函數在子類別首次使用前執行(若父類別有靜態成員被子類別引用)。
7編譯器自動產生預設靜態建構函數若類別包含**帶初始值的靜態欄位**(如 `static int X = 5;`),編譯器會隱式生成靜態建構函數執行初始化。若同時寫了 `static MyClass()`,則合併執行。

執行時機實測:BeforeFieldInit 的影響

C# 編譯器預設為類別標記 `BeforeFieldInit` 屬性,允許 CLR **在任意靜態成員首次被存取前的任意時間** 執行靜態建構函數(可提早、可延遲,利於效能)。若類別**顯式定義了靜態建構函數**,則**移除 `BeforeFieldInit`**,改為**精確語義**:必須在首次存取靜態成員或建立實例**之前**執行,時機更可預測。

// 有靜態建構函數 → 精確語義
class WithStaticCtor
{
    static WithStaticCtor() { Console.WriteLine("靜態建構函數執行"); }
    public static int Value = 10;
}

// 無靜態建構函數,只有靜態欄位初始化 → BeforeFieldInit
class WithoutStaticCtor
{
    public static int Value = Compute(); // 可能在 Main 開始前、或首次存取 Value 時才跑
    static int Compute() { Console.WriteLine("欄位初始化"); return 20; }
}

常見應用場景

  • **單例模式** 的線程安全初始化(配合 `readonly`)。
  • **載入非託管 DLL**(`DllImport` / `NativeLibrary.Load`)。
  • **靜態快取/查找表** 建立(如正則編譯、反射型別掃描)。
  • **設定靜態相依服務**(如 `log4net`、`Serilog` 靜態 Logger 初始化)。

單例模式範例(推薦寫法)

public sealed class Singleton
{
    // 唯讀靜態欄位 + 靜態建構函數 = 完美線程安全延遲初始化
    private static readonly Singleton _instance;
    public static Singleton Instance => _instance;

    static Singleton()
    {
        _instance = new Singleton(); // 只有在第一次存取 Instance 時才執行
    }

    private Singleton() { /* 私有建構函數防外部實例化 */ }

    public void DoWork() => Console.WriteLine("Singleton working...");
}

避坑指南

  • ❌ **靜態建構函數中拋出未處理例外** → 導致 **`TypeInitializationException`** 包裝原始例外,**該類別在該 AppDomain 永久不可用**(後續存取皆拋此異常)。務必 `try-catch` 並記錄錯誤,或提供降級預設值。
  • ❌ **靜態建構函數中執行耗時 IO / 阻塞等待** → 會阻塞所有嘗試使用該類別的線程,造成效能尖峰或死結。改用 `Lazy` 延遲初始化並支援非同步。
  • ❌ **循環靜態相依**(A 的靜態建構函數存取 B 的靜態成員,B 又存取 A)→ 可能導致其中一類別看到未初始化的靜態欄位(預設值 0/null)。設計上避免靜態跨類別強相依。

總結

靜態建構函數是 **C# 型別初始化的核心機制**,提供**線程安全、一次性、延遲執行**的靜態狀態初始化保證。掌握其**觸發時機(BeforeFieldInit)、例外行為、不可繼承、單例應用**等特性,能寫出更健壯、高效的類別庫代碼。記住:**靜態建構函數只做「純初始化」,不做「商業邏輯/IO/阻塞」**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved