若衍生類別有額外清理工作,讓它實作 Dispose 方法:
public class DerivedResourceHog : MyResourceHog
{
private bool _disposed = false;
protected override void Dispose(bool isDisposing)
{
if (_disposed) return;
if (isDisposing) { /* free managed resources */ }
/* free unmanaged resources */
base.Dispose(isDisposing);
_disposed = true;
}
}
注意,衍生與基類各有處理狀態旗標,完全被動。重設旗標掩蓋處理時可能發生的錯誤,且為單一型別處理,而非處理構成物件的所有型別。(譯註:基類與子類各自標記,互不影響。)
物件可能以任何順序被處理,你可能遇到:成員在呼叫 Dispose 前已被處理。Dispose() 可多次呼叫,重複呼叫無事發生。解構函式同樣規則。物件參考存在記憶體時無需檢查 null,但參考的物件可能已處理或解構。
對任何與處理和資源清理相關的方法,必須只釋放資源!切勿在處理過程中添加其他任務。否則會在物件生命週期遇到嚴重複雜問題。物件建立時出生,GC 辨識時死亡。程式無法存取時視為睡眠。解構函式在死亡前有最後一口氣,只應清理非受控資源。若解構函式讓物件重新可存取,物件「復活」——這並不好。
public class BadClass
{
private readonly ArrayList _finalizedList;
private string _msg;
public BadClass(ArrayList badList, string msg) { _finalizedList = badList; _msg = (string)msg.Clone(); }
~BadClass() { _finalizedList.Add(this); } // 物件重新可達,復活!
}
復活物件會導致:GC 相信不再需呼叫解構函式;資源可能已失效;GC 不移除僅被解構佇列參考的物件,但它們可能已解構無法使用。C# 無法控制解構順序,此結構不可靠,切勿嘗試。
IDisposable 成員時添加。IDisposable,無需解構函式,否則限制衍生類別實作標準 Dispose 模式。Dispose 模式,讓你、使用者、衍生類別作者生活輕鬆。