.NET GC(垃圾回收器)只負責受控記憶體。對於檔案控制代碼、資料庫連線、網路 Socket、GDI 物件等非受控資源,GC 「不知情」也「無法預測回收時機」。若不主動釋放,極易造成資源洩漏、連線耗盡、檔案被鎖定等嚴重問題。
TestClass test = new TestClass();
try
{
test.DoSomething();
}
finally
{
if (test is IDisposable d) d.Dispose();
}
using (TestClass test = new TestClass())
{
test.DoSomething();
} // 區塊結束自動呼叫 Dispose()
⚠️ using 無法捕獲例外,若需處理例外仍需搭配 try/catch。
僅實作 void Dispose() 尚不足夠,標準模式需解決三大問題:
public class ResourceHolder : IDisposable
{
// 非受控資源(如 IntPtr handle)
private IntPtr _handle;
// 受控資源(如其他 IDisposable 物件)
private Component _components;
// 防重複釋放旗標
private bool _disposed = false;
// 公開 Dispose(供呼叫端使用)
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 告訴 GC:別再呼叫 Finalize 了
}
// 核心邏輯:disposing=true 來自 Dispose();false 來自 Finalizer
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// 釋放受控資源
_components?.Dispose();
}
// 釋放非受控資源(無論 disposing 為何)
CloseHandle(_handle);
_handle = IntPtr.Zero;
_disposed = true;
}
// Finalizer(析構函數):僅在未呼叫 Dispose 時由 GC 執行
~ResourceHolder()
{
Dispose(false);
}
// 範例:防止釋放後仍被使用
public void DoSomething()
{
if (_disposed) throw new ObjectDisposedException(nameof(ResourceHolder));
// 正常業務邏輯
}
// P/Invoke 範例
[System.Runtime.InteropServices.DllImport("Kernel32")]
private static extern bool CloseHandle(IntPtr handle);
}
| 情境 | Dispose(true) | Dispose(false) |
|---|---|---|
| 受控資源 | ✅ 釋放 | ❌ 不碰(GC 會處理) |
| 非受控資源 | ✅ 釋放 | ✅ 釋放(最後防線) |
| 呼叫來源 | 使用者程式碼 / using | GC Finalizer 執行緒 |
public class DerivedResource : ResourceHolder
{
private ManagedResource _managed;
private NativeResource _native;
private bool _disposed = false;
protected override void Dispose(bool disposing)
{
if (_disposed) return;
try
{
if (disposing)
{
_managed?.Dispose(); // 釋放衍生類自己的受控資源
}
_native?.Close(); // 釋放衍生類自己的非受控資源
}
finally
{
base.Dispose(disposing); // 必須呼叫基類 Dispose
}
_disposed = true;
}
}
IDisposable 的類別務必遵循標準 Dispose PatternDispose(false) 中釋放Dispose() 呼叫 GC.SuppressFinalize(this)_disposed,已釋放則拋 ObjectDisposedExceptionusing 或 try/finally 確保釋放掌握 IDisposable → Dispose Pattern → Finalize 三角關係,是寫出穩健、無資源洩漏 C# 程式的關鍵。記住:受控資源交給 GC,非受控資源自己負責,Dispose 是橋樑,Finalize 是保險。