淺析C# Dispose方法的實現(xiàn)
C# Dispose方法的理解是什么呢?類型的Dispose方法應釋放它擁有的所有資源。它還應該通過調用其父類型的Dispose方法釋放其基類型擁有的所有資源。該父類型的 Dispose 方法應該釋放它擁有的所有資源并同樣也調用其父類型的 Dispose 方法,從而在整個基類型層次結構中傳播此模式。若要確保始終正確地清理資源,Dispose 方法應該可以被多次調用而不引發(fā)任何異常。
Dispose 方法應該為它處置的對象調用 GC.SuppressFinalize 方法。如果對象當前在終止隊列中,GC.SuppressFinalize 防止其 Finalize 方法被調用。請記住,執(zhí)行 Finalize 方法會大大減損性能。如果您的 Dispose 方法已經(jīng)完成了清理對象的工作,那么垃圾回收器就不必再調用對象的 Finalize 方法。
C# Dispose方法的實現(xiàn)時注意
為 System.GC.KeepAlive(System.Object) 方法提供的代碼示例演示了強行垃圾回收如何在回收對象的成員仍在執(zhí)行時引起終結器運行。在較長的Dispose方法末尾***調用KeepAlive方法。
下面的代碼示例旨在闡釋用于為封裝了非托管資源的類實現(xiàn)Dispose方法的建議設計模式。整個 .NET Framework 中都實現(xiàn)了此模式。
資源類通常是從復雜的本機類或 API 派生的,而且必須進行相應的自定義。使用這一代碼模式作為創(chuàng)建資源類的一個起始點,并根據(jù)封裝的資源提供必要的自定義。不能編譯該示例,也不能將其直接用于應用程序。
在此示例中,基類 BaseResource 實現(xiàn)可由該類的用戶調用的公共 Dispose 方法。而該方法又調用 virtual Dispose(bool disposing) 方法(Visual Basic 中為 virtual Dispose(disposing As Boolean))。根據(jù)調用方的標識傳遞 true 或 false。以虛 Dispose 方法為對象執(zhí)行適當?shù)那謇泶a。
Dispose(bool disposing) 以兩種截然不同的方案執(zhí)行。如果 disposing 等于 true,則該方法已由用戶的代碼直接調用或間接調用,并且可釋放托管資源和非托管資源。如果 disposing 等于 false,則該方法已由運行庫從終結器內部調用,并且只能釋放非托管資源。因為終結器不會以任意特定的順序執(zhí)行,所以當對象正在執(zhí)行其終止代碼時,不應引用其他對象。如果正在執(zhí)行的終結器引用了另一個已經(jīng)終止的對象,則該正在執(zhí)行的終結器將失敗。
基類提供的 Finalize 方法或析構函數(shù)在未能調用 Dispose 的情況下充當防護措施。Finalize 方法調用帶有參數(shù)的 Dispose 方法,同時傳遞 false。不應在 Finalize 方法內重新創(chuàng)建 Dispose 清理代碼。調用 Dispose(false) 可以優(yōu)化代碼的可讀性和可維護性。
類 MyResourceWrapper 闡釋如何使用 Dispose 從實現(xiàn)資源管理的類派生。MyResourceWrapper 重寫 virtual Dispose(bool disposing) 方法并為其創(chuàng)建的托管和非托管資源提供清理代碼。MyResourceWrapper 還對其基類 BaseResource 調用 Dispose 以確保其基類能夠適當?shù)剡M行清理。請注意,派生類 MyResourceWrapper 沒有不帶參數(shù)的 Finalize 方法或 Dispose 方法,因為這兩個方法從基類 BaseResource 繼承這些參數(shù)。
C# Dispose方法的實現(xiàn)時注意
此示例中的 protected Dispose(bool disposing) 方法不強制線程安全,因為無法從用戶線程和終結器線程同時調用該方法。另外,使用 BaseResource 的客戶端應用程序應從不允許多個用戶線程同時調用 protected Dispose(bool disposing) 方法。應用程序或類庫的設計原則為:應用程序或類庫應只允許一個線程擁有資源的生存期,并且應在不再需要資源時調用 Dispose。根據(jù)資源的不同,在處置資源時進行異步線程訪問可能會帶來安全風險。開發(fā)人員應仔細檢查自己的代碼,以確定***的方法來強制線程安全
C# Dispose方法的實現(xiàn)實例
- // 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.
C# Dispose方法的實現(xiàn)以及C# Dispose方法的一些基本內容就向你介紹到這里,希望對你了解和學習C# Dispose方法有所幫助。
【編輯推薦】