MSDNios
類型的 Dispose 方法應釋放它擁有的全部資源。它還應該經過調用其父類型的 Dispose 方法釋放其基類型擁有的全部資源。該父類型的 Dispose 方法應該釋放它擁有的全部資源並一樣也調用其父類型的 Dispose 方法,從而在整個基類型層次結構中傳播此模式。若要確保始終正確地清理資源,Dispose 方法應該能夠被屢次調用而不引起任何異常。程序員
要點 |
---|
C++ 程序員不該該使用本主題。而應參見 Destructors and Finalizers in Visual C++。在 .NET Framework 2.0 版中,C++ 編譯器爲實現資源的肯定性處置提供支持,而且不容許直接實現Dispose 方法。設計模式 |
Dispose 方法應該爲它處置的對象調用 GC.SuppressFinalize 方法。若是對象當前在終止隊列中,GC.SuppressFinalize 防止其 Finalize 方法被調用。請記住,執行 Finalize 方法會大大減損性能。若是您的 Dispose 方法已經完成了清理對象的工做,那麼垃圾回收器就沒必要再調用對象的 Finalize 方法。安全
注意 |
---|
爲 System.GC.KeepAlive(System.Object) 方法提供的代碼示例演示了強行垃圾回收如何在回收對象的成員仍在執行時引發終結器運行。在較長的 Dispose 方法末尾最好調用 KeepAlive 方法。app |
下面的代碼示例旨在闡釋用於爲封裝了非託管資源的類實現 Dispose 方法的建議設計模式。整個 .NET Framework 中都實現了此模式。異步
資源類一般是從複雜的本機類或 API 派生的,並且必須進行相應的自定義。使用這一代碼模式做爲建立資源類的一個起始點,並根據封裝的資源提供必要的自定義。不能編譯該示例,也不能將其直接用於應用程序。ide
在此示例中,基類 BaseResource 實現可由該類的用戶調用的公共 Dispose 方法。而該方法又調用 virtual Dispose(bool disposing) 方法(Visual Basic 中爲 virtual Dispose(disposing As Boolean))。根據調用方的標識傳遞 true 或 false。以虛 Dispose 方法爲對象執行適當的清理代碼。函數
Dispose(bool disposing) 以兩種大相徑庭的方案執行。若是 disposing 等於 true,則該方法已由用戶的代碼直接調用或間接調用,而且可釋放託管資源和非託管資源。若是 disposing 等於false,則該方法已由運行庫從終結器內部調用,而且只能釋放非託管資源。由於終結器不會以任意特定的順序執行,因此當對象正在執行其終止代碼時,不該引用其餘對象。若是正在執行的終結器引用了另外一個已經終止的對象,則該正在執行的終結器將失敗。性能
基類提供的 Finalize 方法或析構函數在未能調用 Dispose 的狀況下充當防禦措施。Finalize 方法調用帶有參數的 Dispose 方法,同時傳遞 false。不該在 Finalize 方法內從新建立 Dispose 清理代碼。調用 Dispose(false) 能夠優化代碼的可讀性和可維護性。優化
類 MyResourceWrapper 闡釋如何使用 Dispose 從實現資源管理的類派生。MyResourceWrapper 重寫 virtual Dispose(bool disposing) 方法併爲其建立的託管和非託管資源提供清理代碼。MyResourceWrapper 還對其基類 BaseResource 調用 Dispose 以確保其基類可以適當地進行清理。請注意,派生類 MyResourceWrapper 沒有不帶參數的 Finalize 方法或 Dispose 方法,由於這兩個方法從基類 BaseResource 繼承這些參數。
注意 |
---|
此示例中的 protected Dispose(bool disposing) 方法不強制線程安全,由於沒法從用戶線程和終結器線程同時調用該方法。另外,使用 BaseResource 的客戶端應用程序應從不容許多個用戶線程同時調用 protected Dispose(bool disposing) 方法。應用程序或類庫的設計原則爲:應用程序或類庫應只容許一個線程擁有資源的生存期,而且應在再也不須要資源時調用 Dispose。根據資源的不一樣,在處置資源時進行異步線程訪問可能會帶來安全風險。開發人員應仔細檢查本身的代碼,以肯定最佳的方法來強制線程安全。 |
// 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 方法比調用 Dispose 方法更容易,則能夠向基類型添加一個公共 Close 方法。Close 方法又會調用沒有參數的 Dispose 方法,該方法能夠執行正確的清理操做。下面的代碼示例闡釋了 Close 方法。
// 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(); }