建議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個建議》陸敏技