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

C# 解構子深度解析:非決定性最終化、GC 互動與 IDisposable 最佳實務

     編輯:關於C#

解構子語法與限制


class ResourceHolder {
    private IntPtr _nativeHandle;

    ~ResourceHolder() { // 語法:~ClassName()
        // 僅清理非受控資源
        if (_nativeHandle != IntPtr.Zero) {
            NativeMethods.CloseHandle(_nativeHandle);
            _nativeHandle = IntPtr.Zero;
        }
    }
}
  • 名稱固定為 ~ + 類別名稱,不可自訂。
  • 無參數、無回傳值、無存取修飾詞、不可多載、不可繼承、不可顯式呼叫。
  • 編譯器轉換為 protected override void Finalize()。

非決定性執行特性

特性說明
執行時機GC 判定物件無法觸達後,由 Finalizer Thread 排程執行
順序不保證多個物件解構子執行順序不可預測
可能不執行進程強制終止、AppDomain 卸載、嚴重錯誤時
例外處理解構子拋出未捕捉例外 → 進程終止 (NET Framework) 或被吞噬 (.NET Core+)
復活物件解構子中將 this 指派給靜態欄位 → 物件復活,下次 GC 再次最終化

為什麼不建議依賴解構子釋放關鍵資源?

  1. 延遲釋放:資源佔用時間不可控,可能耗盡系統資源 (連線池、檔案鎖)。
  2. 順序風險:解構子執行時其他受控物件可能已被最終化,存取它們不安全。
  3. 效能影響:有解構子的物件需進入 Finalization Queue,GC 代數提升較慢,增加記憶體壓力。

標準釋放模式:IDisposable + 解構子雙重保險


public sealed class FileManager : IDisposable {
    private FileStream _stream;
    private bool _disposed;

    public FileManager(string path) => _stream = File.Open(path, FileMode.Open);

    // 公開釋放方法:決定性釋放
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this); // 告訴 GC 不需呼叫解構子
    }

    // 核心邏輯:disposing=true 來自 Dispose(),false 來自解構子
    private void Dispose(bool disposing) {
        if (_disposed) return;
        if (disposing) {
            // 釋放受控資源 (其他 IDisposable 物件)
            _stream?.Dispose();
        }
        // 釋放非受控資源 (無論 disposing)
        _stream = null;
        _disposed = true;
    }

    // 解構子:最後防線,僅釋放非受控資源
    ~FileManager() => Dispose(false);
}

using 陳述式:語法糖保證釋放


// 編譯器展開為 try/finally 區塊
using (var fm = new FileManager("data.txt")) {
    fm.Process();
}
// 等同於
var fm = new FileManager("data.txt");
try { fm.Process(); }
finally { fm?.Dispose(); }

現代 .NET 進階釋放模式

  • IAsyncDisposable (C# 8/.NET Core 3.0):await using 非同步釋放。
  • SafeHandle 衍生類別:包裝非受控控制代碼,內建最終化邏輯,避免手寫解構子。
  • MemoryManager<T>:自訂記憶體管理釋放邏輯。

最佳實務檢核表

  1. [ ] 實作 IDisposable 而非單獨依賴解構子。
  2. [ ] Dispose() 可重複呼叫不拋出例外 (冪等)。
  3. [ ] Dispose() 呼叫 GC.SuppressFinalize(this)。
  4. [ ] 解構子僅清理非受控資源,呼叫 Dispose(false)。
  5. [ ] 密封類別 (sealed) 簡化釋放邏輯 (無衍生類別需考慮)。
  6. [ ] 公開 API 文件註解說明「必須呼叫 Dispose」或「支援 using」。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved