建議49:在Dispose模式中應提取一個受保護的虛方法
在標准的Dispose模式中,真正的IDisposable接口的Dispose方法並沒有做實際的清理工作,它其實是調用了下面的這個帶bool參數且受保護的的虛方法:
/// <summary> /// 非密封類修飾用protected virtual /// 密封類修飾用private /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) {
//省略代碼 }
之所以提供這樣一個受保護的虛方法,是因為考慮了這個類型會被其他類型繼承的情況。如果類型存在一個子類,子類也許會實現自己的Dispose模式。受保護的虛方法用來提醒子類:必須在自己的清理方法時注意到父類的清理工作,即子類需要在自己的釋放方法中調用base.Dispose方法。
public class DerivedSampleClass : SampleClass { //子類的非托管資源 private IntPtr derivedNativeResource = Marshal.AllocHGlobal(100); //子類的托管資源 private AnotherResource derivedManagedResource = new AnotherResource(); //定義自己的是否釋放的標識變量 private bool derivedDisposed = false; /// <summary> ///重寫父類Dispose方法 /// </summary> /// <param name="disposing"></param> protected override void Dispose(bool disposing) { if (derivedDisposed) { return; } if (disposing) { // 清理托管資源 if (derivedManagedResource != null) { derivedManagedResource.Dispose(); derivedManagedResource = null; } } // 清理非托管資源 if (derivedNativeResource != IntPtr.Zero) { Marshal.FreeHGlobal(derivedNativeResource); derivedNativeResource = IntPtr.Zero; } //調用父類的清理代碼 base.Dispose(disposing); //讓類型知道自己已經被釋放 derivedDisposed = true; } } public class SampleClass : IDisposable { //演示創建一個非托管資源 private IntPtr nativeResource = Marshal.AllocHGlobal(100); //演示創建一個托管資源 private AnotherResource managedResource = new AnotherResource(); private bool disposed = false; /// <summary> /// 實現IDisposable中的Dispose方法 /// </summary> public void Dispose() { //必須為true Dispose(true); //通知垃圾回收機制不再調用終結器(析構器) GC.SuppressFinalize(this); } /// <summary> /// 不是必要的,提供一個Close方法僅僅是為了更符合其他語言(如 /// C++)的規范 /// </summary> public void Close() { Dispose(); } /// <summary> /// 必須,防止程序員忘記了顯式調用Dispose方法 /// </summary> ~SampleClass() { //必須為false Dispose(false); } /// <summary> /// 非密封類修飾用protected virtual /// 密封類修飾用private /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) { if (disposed) { return; } if (disposing) { // 清理托管資源 if (managedResource != null) { managedResource.Dispose(); managedResource = null; } } // 清理非托管資源 if (nativeResource != IntPtr.Zero) { Marshal.FreeHGlobal(nativeResource); nativeResource = IntPtr.Zero; } //讓類型知道自己已經被釋放 disposed = true; } public void SamplePublicMethod() { if (disposed) { throw new ObjectDisposedException("SampleClass", "SampleClass is disposed"); } //省略 } } class AnotherResource : IDisposable { public void Dispose() { } }
如果不為類提供這個受保護的虛方法,很有可能讓開發者設計子類的時候忽略掉父類的清理工作。所以要在類型的Dispose模式中提供一個受保護的虛方法。
轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技