实现IDisposable接口最佳方式

JerryXia 发表于 , 阅读 (2,012)

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(),提高了非托管资源的使用效率并提升了系统性能。

添加新评论