1 使用System.IDisposable接口替代析构函数。IDisposable接口声明了一个方法Dispose(),他不带参数,
返回void。假定有一个类ResourceGobbler,它使用某些外部资源,且实现IDisposable接口。如果要实例
化这个类的实例,使用它,然后释放它,就可以使用下面的代码:
class ResourceGobbler:IDisposable
{
public void Dispose()
{
//implementation
}
}
//另一端引用代码
ResourceGobbler theInstance=null;
try
{
theInstance=new ResourceGobbler();
//do your processing
finally
{
if(theInstance!=null)theInstance.Dispose();
}
}
如果重视要重复这样的结构,代码就很容易被混淆。C#提供了一种语法,可以确保在对象引用超出作用域
时,在执行IDisposable接口的对象上自动调用Dispose()。该语法使用了Using关键字来完成这一工作
下面的代码生成与try块相对应的IL代码:
using(ResourceGobbler theInstance=new ResourceGobbler())
{
//do your processing
}
using语句的后面是一对圆括号,其中是引用变量的声明和实例化,该语句使变量放在其后的语句块中。
另外,在变量超出作用域时,即使出现异常,也会自动调用其Dispose()方法。如果已经使用try块来捕
获其他异常,就会比较清晰,如果避免使用using,仅在已有的try块finally子句中调用Dispose(),可
以避免进行额外的缩进。
2 实现IDisposable接口和析构函数
IDisposable接口提供了一种机制,允许类的用户控制释放资源的时间,但需要确保执行Dispose(),一
般情况下,最好的方法是与析构函数配合使用,如下例子:
public class ResourceHolder:IDisposable
{
private bool isDispose=false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!isDisposed)
{
if(disposing)
{
//cleanup managed objects by calling their Dispose() methods.
}
//cleanup unmanaged objects
}
isDisposed=true;
}
~ResourceHolder()
{
Dispose(false);
}
public void SomeMethod()
{
//Ensure object not already disposed before execution of any method
if(isDisposed)
{
throw new ObjectDisposedException("ResourceHolder");
}
}
}
可以看出Dispose()有第二个Protected重载方法,他带一个bool参数,这是真正完成清理工作方法。
Dispose(bool)有析构函数和IDisposable.Dispose()调用。这个方式的重点确保所有的清理代码都放在
一个地方。
传递给Dispose(bool)的参数表示Dispose(bool)是由析构函数调用,还是由IDisposable.Dispose()调
用——Dispose(bool)不应从代码的其他地方调用,其原因是:
(1)如果客户调用IDisposable.Dispose(),该客户就指定应清理所有与该对象相关的资源,宝库托管和
非托管资源。
(2) 如果调用了析构函数,原则上所有的资源仍需要清理,但是在这种情况下,析构函数必须由垃圾
收集器调用,而且不应访问其他托管的对象,因为我们不再能确定他们的状态了,在这种情况下,
最好清理已知的未托管资源,希望引用的托管对象还有析构函数,执行自己的清理过程。