首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

.NET 靜態欄位初始化為當前類型實例的記憶體模型解析

     編輯:程式設計綜合問答

程式碼範例

public class Test
{
    public int C = 0;
    public static Test My = new Test(2); // 靜態欄位初始化為自身實例
    public int X;
    public Test(int x) { X = x; }
}

class Program
{
    static void Main()
    {
        Test me = Test.My;
        Console.WriteLine(me.X); // 輸出 2
    }
}

執行順序與記憶體分配

  1. 型別初始化(.cctor):CLR 在第一次存取 `Test` 型別的靜態成員前,執行靜態建構函數(``)。
  2. 靜態欄位初始化:按原始碼順序執行靜態欄位初始化器。執行到 `public static Test My = new Test(2);` 時:
  • 在 Managed Heap 上配置一個 `Test` 物件。
  • 呼叫實例建構函數 `Test(2)`,將 `X=2` 寫入該物件。
  • 將物件參考賦值給靜態欄位 `My`(儲存在型別的靜態資料區)。

此時 `My` 已指向一個完整初始化的 `Test` 實例。

為何「自己能調用自己」?

  • 靜態欄位初始化器執行時,型別 `Test` 已經載入完成,實例建構函數可正常呼叫。
  • 這不是遞迴:不是在建構函數內部存取 `My`,而是在型別初始化階段建立一個實例並存入靜態欄位。
  • 若在實例建構函數中存取 `Test.My`,則會觸發型別初始化(若尚未完成),導致遞迴或取得未完全初始化的實例(危險)。

三種建構函數澄清

類型語法用途呼叫時機
靜態建構函數`static Test() { }`初始化靜態欄位、執行一次性邏輯型別第一次被存取前,CLR 自動呼叫,執行一次
實例建構函數`public Test() { }`初始化實例欄位每次 `new Test()` 時呼叫
私有建構函數`private Test() { }`單例模式、工廠模式、防止外部實例化僅類別內部可呼叫

最佳實踐

  • 單例模式推薦使用 Lazy<T> 或雙重檢查鎖定,避免靜態初始化順序陷阱。
  • 靜態欄位若需複雜初始化,改在靜態建構函數中執行,可捕獲異常並控制順序。
  • 避免在實例建構函數中存取同類別的靜態欄位(特別是自身實例)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved