實作 Dispose 方法
型別的 Dispose 方法應該釋放它所擁有的所有資源,它也應該藉由呼叫其基底型別 (Base Type) 之父型別的 Dispose 方法,來釋放其基底型別所擁有的所有資源。父型別的 Dispose 方法應釋放它擁有的所有資源,接著呼叫其父型別的 Dispose 方法,將此模式傳播到整個基底型別的階層架構中。若要確保資源永遠都能適當清除,Dispose 方法應該能夠被呼叫多次而不會擲回例外狀況。
重要資訊 |
---|
C++ 程式設計人員不應該使用這個說明主題,而應該參閱 Destructors and Finalizers in Visual C++。在 .NET Framework 2.0 版中,C++ 編譯器可讓您實作決定性的資源處置,但不允許直接實作 Dispose 方法。 |
Dispose 方法應該呼叫它正在處置 (Dispose) 之物件的 GC.SuppressFinalize 方法。如果物件目前正在最終處理佇列,GC.SuppressFinalize 會防止它的 Finalize 方法被呼叫。請記住,執行 Finalize 方法將付出很大的效能代價。如果您的 Dispose 方法已完成執行清除物件的工作,記憶體回收行程就不需要呼叫該物件的 Finalize 方法。
注意事項 |
---|
此處所提供的 System.GC.KeepAlive(System.Object) 方法程式碼範例,顯示積極記憶體回收如何在被回收的物件仍在執行時,即讓完成項開始執行。在冗長的 Dispose 方法結尾處呼叫 KeepAlive 方法,這是個不錯的做法。 |
下列程式碼範例的目的是要說明建議使用的設計模式,這種模式可為封裝 Unmanaged 資源的類別實作 Dispose 方法。.NET Framework 都是實作這種模式。
資源類別通常是從複雜的原生類別或 API 衍生而來,因此必須依照情況加以自訂。請將這個程式碼模式當做建立資源類別的起始點,並且根據您正在封裝的資源,提供必要的自訂。您不能編譯這個範例並直接在應用程式中使用它。
在這個範例中,基底類別 BaseResource
會實作一個可讓類別使用者呼叫的公用 Dispose 方法。它會接著呼叫 virtual Dispose(bool disposing) 方法 (在 Visual Basic 中為 virtual Dispose(disposing As Boolean))。根據呼叫端的識別 (Identity) 來傳遞 true 或 false。物件適當的清除程式碼會在虛擬 Dispose 方法中執行。
Dispose(bool disposing) 可在兩種不同的案例中執行。如果 disposing 等於 true,表示方法是由使用者的程式碼直接或間接呼叫的,因此可以處置 Managed 和 Unmanaged 資源。如果 disposing 等於 false,表示方法是由執行階段從完成項內部呼叫的,因此只能處置 Unmanaged 資源。當物件正在執行它的最終處理程式碼時,它不可以參考其他物件,因為完成項不會依照任何特定順序執行。如果正在執行的完成項參考的另一個物件已經做過最終處理,那麼正在執行的完成項將會失敗。
基底類別提供 Finalize 方法或解構函式,做為萬一沒有呼叫 Dispose 時的防護措施。Finalize 方法會呼叫使用參數的 Dispose 方法,以傳遞 false。請勿在 Finalize 方法內重新建立 Dispose 清除程式碼。呼叫 Dispose(false) 對於程式碼的可讀性和可維護性是最佳方式。
MyResourceWrapper
類別說明了如何從使用 Dispose 實作資源管理的類別中衍生新類別的方法。MyResourceWrapper
會覆寫 virtual Dispose(bool disposing) 方法,並提供它所建立的 Managed 和 Unmanaged 資源的清除程式碼。MyResourceWrapper
也會在自己的基底類別 BaseResource
上呼叫 Dispose,以確保其基底有機會能正常地進行清除工作。請注意,衍生類別 MyResourceWrapper
並沒有不含參數的 Finalize 或 Dispose 方法,因為它可以從其基底類別 BaseResource
繼承這兩個方法。
注意事項 |
---|
此一範例中的 protected Dispose(bool disposing) 方法並不會強制使用執行緒安全,因為此方法無法同時從使用者執行緒和完成項執行緒呼叫。此外,使用 |
' Design pattern for the base class.
' By implementing IDisposable, you are announcing that instances
' of this type allocate scarce resources.
Public Class BaseResource
Implements IDisposable
' Pointer to an external unmanaged resource.
Private handle As IntPtr
' Other managed resource this class uses.
Private Components As Component
' Track whether Dispose has been called.
Private disposed As Boolean = False
' Constructor for the BaseResource Object.
Public Sub New()
' Insert appropriate constructor code here.
End Sub
' Implement IDisposable.
' Do not make this method Overridable.
' A derived class should not be able to override this method.
Public Overloads Sub Dispose()Implements IDisposable.Dispose
Dispose(true)
' Take yourself off of the finalization queue
' to prevent finalization code for this object
' from executing a second time.
GC.SuppressFinalize(Me)
End Sub
' Dispose(disposing As Boolean) executes in two distinct scenarios.
' If disposing is true, the method has been called directly
' or indirectly by a user's code. Managed and unmanaged resources
' can be disposed.
' If disposing equals false, the method has been called by the runtime
' from inside the finalizer and you should not reference other
' objects. Only unmanaged resources can be disposed.
Protected Overloads Overridable Sub Dispose(disposing As Boolean)
' Check to see if Dispose has already been called.
If Not (Me.disposed) Then
' If disposing equals true, dispose all managed
' and unmanaged resources.
If (disposing) Then
' Dispose managed resources.
Components.Dispose()
End If
' Release unmanaged resources. If disposing is false,
' only the following code is executed.
CloseHandle(handle)
handle = IntPtr.Zero
' Note that this is not thread safe.
' Another thread could start disposing the object
' after the managed resources are disposed,
' but before the disposed flag is set to true.
' If thread safety is necessary, it must be
' implemented by the client.
End If
Me.disposed = true
End Sub
' This Finalize method will run only if the
' Dispose method does not get called.
' By default, methods are NotOverridable.
' This prevents a derived class from overriding this method.
Protected Overrides Sub Finalize()
' Do not re-create Dispose clean-up code here.
' Calling Dispose(false) is optimal in terms of
' readability and maintainability.
Dispose(false)
End Sub
' Allow your Dispose method to be called multiple times,
' but throw an exception if the object has been disposed.
' Whenever you do something with this class,
' check to see if it has been disposed.
Public Sub DoSomething()
If Me.disposed Then
Throw New ObjectDisposedException()
End if
End Sub
End Class
' Design pattern for a derived class.
' Note that this derived class inherently implements the
' IDisposable interface because it is implemented in the base class.
Public Class MyResourceWrapper
Inherits BaseResource
' A managed resource that you add in this derived class.
private addedManaged As ManagedResource
' A native unmanaged resource that you add in this derived class.
private addedNative As NativeResource
' Track whether Dispose has been called.
Private disposed As Boolean = False
' Constructor for the MyResourceWrapper object.
Public Sub New()
MyBase.New()
' Insert appropriate constructor code here for the
' added resources.
End Sub
Protected Overloads Overrides Sub Dispose(disposing As Boolean)
If Not (Me.disposed) Then
Try
If disposing Then
' Release the managed resources you added in
' this derived class here.
addedManaged.Dispose()
End If
' Release the native unmanaged resources you added
' in this derived class here.
CloseHandle(addedNative)
Me.disposed = true
Finally
' Call Dispose on your base class.
MyBase.Dispose(disposing)
End Try
End If
End Sub
End Class
' This derived class does not have a Finalize method
' or a Dispose method without parameters because it
' inherits them from the base class.
// Design pattern for the base class.
// By implementing IDisposable, you are announcing that instances
// of this type allocate scarce resources.
public class BaseResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component Components;
// Track whether Dispose has been called.
private bool disposed = false;
// Constructor for the BaseResource object.
public BaseResource()
{
// Insert appropriate constructor code here.
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
Components.Dispose();
}
// Release unmanaged resources. If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note that this is not thread safe.
// Another thread could start disposing the object
// after the managed resources are disposed,
// but before the disposed flag is set to true.
// If thread safety is necessary, it must be
// implemented by the client.
}
disposed = true;
}
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~BaseResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
// Allow your Dispose method to be called multiple times,
// but throw an exception if the object has been disposed.
// Whenever you do something with this class,
// check to see if it has been disposed.
public void DoSomething()
{
if(this.disposed)
{
throw new ObjectDisposedException();
}
}
}
// Design pattern for a derived class.
// Note that this derived class inherently implements the
// IDisposable interface because it is implemented in the base class.
public class MyResourceWrapper: BaseResource
{
// A managed resource that you add in this derived class.
private ManagedResource addedManaged;
// A native unmanaged resource that you add in this derived class.
private NativeResource addedNative;
private bool disposed = false;
// Constructor for this object.
public MyResourceWrapper()
{
// Insert appropriate constructor code here.
}
protected override void Dispose(bool disposing)
{
if(!this.disposed)
{
try
{
if(disposing)
{
// Release the managed resources you added in
// this derived class here.
addedManaged.Dispose();
}
// Release the native unmanaged resources you added
// in this derived class here.
CloseHandle(addedNative);
this.disposed = true;
}
finally
{
// Call Dispose on your base class.
base.Dispose(disposing);
}
}
}
}
// This derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits
// them from the base class.
實作 Close 方法
對於呼叫 Close 方法比呼叫 Dispose 方法來得自然的型別,請將公用 Close 方法加入至基底型別中。Close 方法會接著呼叫不含參數的 Dispose 方法,以執行正確的清除作業。下列程式碼範例是在說明 Close 方法。
' Do not make this method Overridable.
' A derived class should not be allowed
' to override this method.
Public Sub Close()
' Calls the Dispose method without parameters.
Dispose()
End Sub
// Do not make this method virtual.
// A derived class should not be allowed
// to override this method.
public void Close()
{
// Calls the Dispose method without parameters.
Dispose();
}
請參閱
參考
GC.SuppressFinalize Method
Destructors and Finalizers in Visual C++
實作 Finalize 和 Dispose 以清除 Unmanaged 資源