实现IDisposable接口最佳方式
Finalize可以通过垃圾回收进行自动的调用,而Dispose需要被代码显示的调用,所以,为了保险起见,对于一些非托管资源,还是有必要实现终结器的。
也就是说,如果我们忘记了显示的调用Dispose,那么垃圾回收也会调用Finalize,从而保证非托管资源的回收。
MSDN上给我们提供了一种很好的模式来实现IDisposable接口来结合Dispose和Finalize,看下面的代码:
class MyResourceWrapper:IDisposable
{
private bool IsDisposed=false;
public void Dispose()
{
Dispose(true);
//tell GC not invoke Finalize method
GC.SuppressFinalize(this);
}
protected void Dispose(bool Disposing)
{
if(!IsDisposed)
{
if(Disposing)
{
//clear managed resources
}
//clear unmanaged resources
}
IsDisposed=true;
}
~MyResourceWrapper()
{
Dispose(false);
}
}
在这个模式中,void Dispose(bool Disposing)函数通过一个Disposing参数来区别当前是否是被Dispose()调用。如果是被Dispose()调用,那么需要同时释放托管和非托管的资源。如果是被终结器调用了,那么只需要释放非托管的资源即可。Dispose()函数是被其它代码显式调用并要求释放资源的,而Finalize是被GC调用的。
另外,由于在Dispose()中已经释放了托管和非托管的资源,因此在对象被GC回收时再次调用Finalize是没有必要的,所以在Dispose()中调用GC.SuppressFinalize(this)避免重复调用Finalize。同样,因为IsDisposed变量的存在,资源只会被释放一次,多余的调用会被忽略。
所以这个模式的优点可以总结为:
如果没有显示的调用Dispose(),未释放托管和非托管资源,那么在垃圾回收时,还会执行Finalize(),释放非托管资源,同时GC会释放托管资源。
如果调用了Dispose(),就能及时释放了托管和非托管资源,那么该对象被垃圾回收时,就不会执行Finalize(),提高了非托管资源的使用效率并提升了系统性能。