建構函式負責「出生」初始化,解構函式負責「亡故」清理。在 .NET 托管環境下,記憶體回收由 GC 自動處理,解構函式轉型為非受控資源釋放的最終防線。本文詳細剖析實例/靜態建構函式執行順序、繼承鏈呼叫機制、解構函式與 Finalize 的關係、IDisposable 模式、GC 抑制終結化等核心主題。
public 預設建構函式,僅呼叫 base()。this() 與 base()
class Base {
public Base() { Console.WriteLine("Base()"); }
public Base(string s) { Console.WriteLine($"Base({s})"); }
}
class Derived : Base {
public Derived() : base() { Console.WriteLine("Derived()"); } // 明確呼叫 base()
public Derived(string s) : this() { Console.WriteLine($"Derived({s})"); } // 連結同類別其他建構函式
}
執行順序:欄位初始化 → base(...) → 本建構函式主體。
class Base {
public Base() { Print(); }
public virtual void Print() { }
}
class Derived : Base {
int x = 1; // 欄位初始化器
int y;
public Derived() {
y = -1; // 建構函式主體
Print();
}
public override void Print() => Console.WriteLine($"x={x}, y={y}");
}
new Derived();
// 輸出:x=1, y=0 (基類建構函式中呼叫虛擬方法,衍生類覆寫執行,y 尚未指派)
// 輸出:x=1, y=-1 (衍生類建構函式完成後再次呼叫)
鐵律:欄位初始化器在 base() 之前執行,建構函式主體在 base() 之後。
private 建構函式:防止外部實例化,配合靜態工廠方法或單例模式。internal:限制同組件實例化。protected:允許衍生類實例化,常用於抽象基類。static,無參數、無存取修飾符、不可呼叫。.cctor)IL 層面稱為 .cctor(class constructor),包含靜態欄位初始化器與靜態建構函式主體。標記 beforefieldinit 的型別(無靜態建構函式)執行時機更靈活;有靜態建構函式則移除該旗標,確保精確語意。
// C# 原始碼
~MyClass() { Console.WriteLine("Destructor"); }
// IL 降級(編譯器自動產生)
protected override void Finalize() {
try { Console.WriteLine("Destructor"); }
finally { base.Finalize(); }
}
Finalize,強制使用 ~ClassName() 語法。~Derived()(編譯器自動在 finally 呼叫 base.Finalize())。Finalize。結論:終結化使物件至少經歷兩次 GC 週期,增加延遲與記憶體壓力,且執行順序不確定、執行緒不安全。
IDisposable 模式:確定性釋放非受控資源
public sealed class ResourceHolder : IDisposable
{
private IntPtr _handle; // 非受控資源
private bool _disposed;
public ResourceHolder() => _handle = NativeMethods.Acquire();
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 告訴 GC 不需呼叫 Finalize
}
private void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing) {
// 釋放受控資源(其他 IDisposable 物件)
}
// 釋放非受控資源
if (_handle != IntPtr.Zero) {
NativeMethods.Release(_handle);
_handle = IntPtr.Zero;
}
_disposed = true;
}
~ResourceHolder() => Dispose(false); // 終結化備援
}
using 語法糖與 await using (C# 8+)
using (var res = new ResourceHolder()) { /* ... */ } // 自動呼叫 Dispose()
// 或
await using var res = new AsyncResourceHolder(); // 非同步釋放
SafeHandle:框架級非受控資源封裝SafeHandleZeroOrMinusOneIsInvalid / SafeHandleMinusOneIsInvalid。ReleaseHandle() 釋放邏輯。Finalize/Dispose 的錯誤風險。GC.Collect()?GC.Collect()、GC.WaitForPendingFinalizers()、GC.WaitForFullGCComplete()。record、init、Primary Constructor (C# 12) 減少建構函式樣板
// C# 12 Primary Constructor
public class Person(string Name, int Age)
{
public string Name { get; init; } = Name;
public int Age { get; init; } = Age;
}
// record 自動產生建構函式、不可變屬性、with-expression、相等性比較
public record Person(string Name, int Age);
建構函式確立物件不變條件,解構函式/IDisposable 守護非受控資源。掌握初始化順序、靜態建構觸發時機、終結化佇列機制、Dispose 模式與 SafeHandle 最佳實務,並善用現代語法簡化樣板碼,即能寫出資源安全、效能穩定、易於維護的專業級 C# 程式碼。