用IDisposable接口釋放.NET資源

使用Dispose 模式能夠適當地釋放資源,但會增加系統開銷。
by Mickey Williams

通過使用Dispose模式可以適當地釋放非內存資源,比如數據庫連接、Win32 interop組件和操作系統的句柄。你不要指望垃圾收集器能夠立即將資源釋放掉,因爲垃圾收集器是由於管制堆(Managed Heap)的內存緊張時才觸發的。你可以快速消耗掉例如數據庫連接等少量資源,但會給程序的擴展性造成副面影響。在不必要的時候不能實現Dispose模式,因爲它可能會增加系統開銷,而這在很多情況下是可以避免的。

在.NET當中Dispose 模式是由一個IDisposable接口來實現的,它包括一個簡單的方法--Dispose:

interface IDisposable
{
	void Dispose();
} 

最明顯的例子是在一個類裏當類的實例搶佔住一個非管制資源(unmanaged resource)時必須實現IDisposable,比如一個本地數據連接或是操作系統的句柄。

另外,記下一個經常被忽略的應該實現IDisposable接口的例子。當一個類實現IDisposable時,實例的正確用法是當對象不在需要時調用Dispose方法刪除它,因此,在你實現一個類,而該類又包含其他實現IDisposable的類時,必須調用Dispose方法。這通常意味着在該類中你必須實現IDisposable,即使它無法直接處理非管制資源。

以下是一個實現IDisposable接口的典型模式:

public class SlalomRacer: IDisposable
{
    bool _disposed = false;

    public bool IsDisposed
    {
        get { return _disposed; }
        set { _disposed = value; }
    }

    ~SlalomRacer()
    {
        InternalDispose(false);
    }

    public void Dispose()
    {
        InternalDispose(true);
    }

    protected void InternalDispose(bool disposing)
    {
        if(disposing)
        {
            GC.SuppressFinalize(this);
            _managedThing.Dispose();
        }
        _unmanagedThing.Dispose();
    }
    [...]
}

在前面的代碼片斷中,當IDisposable被實現時,可以通過兩種方法調用disposal代碼。首先,如果你直接調用Dispose方法,所有管制和非管制對象均會被列爲被清除目標。可以看到終止操作會執行一個阻止對象被清除掉的優化的步驟。還注意到可以安全地多次調用Dispose方法。調用dispose方法之後,會使用一個標誌來確保這個對象上的任何一個方法都不能被調用,示例代碼如下:

public void SeekHotTub()
{
    if(IsDisposed)
        throw new ObjectDisposedException("BT");
}

ObjectDisposedException會提醒你前面已經使用了一個disposed對象。在一個使用過disposed對象上調用其他方法時引發異常是完全有必要的--畢竟,你不能再次使用這些disposed對象。

其次,如果你不調用這個Dispose方法,終止操作會自己調用Dispose(false),它會採用一個和前段代碼稍有不同的代碼路徑。第一,不清除那些管制對象,即使他們也實現了IDisposable接口。你無法確定對象引用是有效的--這些對象可能在等待操作的終止,或者已經被終止了。第二,也沒有必要去調用GC.SuppressFinalization,因爲這些對象已被終止使用了。

最後,如果你在使用C#,你應該利用其語言固有的對IDisposable接口的支持來實現對象清除,你可以使用以下聲明:

using(SlalomRacer mickey = new SlalomRacer())
{
    // use mickey here
    mickey.RunGates();
    mickey.GetStitches();
}
// mickey disposed automatically here

C#編輯器會適當地發出調用Dispose方法的IL代碼,即使會引發異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章