我问了一个关于returning a Disposable (IDisposable) object from a function的问题,但我认为如果我在那里提出这个问题,我会混淆讨论。
我创建了一些示例代码:
class UsingTest
{
public class Disposable : IDisposable
{
public void Dispose()
{
var i = 0;
i++;
}
}
public static Disposable GetDisposable(bool error)
{
var obj = new Disposable();
if (error)
throw new Exception("Error!");
return obj;
}
}我故意这样编写,因为然后我调用:
using (var tmp = UsingTest.GetDisposable(true)) { }使用调试器时,我注意到即使我们已经实例化了一个Disposable对象,Dispose方法也从不执行。如果我正确理解了Dispose的用途,如果这个类实际上有打开的句柄之类的,那么我们不会在完成它们之后立即关闭它们。
我问这个问题是因为这个行为符合我的预期,但在对相关问题的回答中,人们似乎表明using会处理一切。
如果using仍然以某种方式处理这一切,有人能解释一下我错过了什么吗?但是,如果这段代码确实可能导致资源泄漏,您会如何建议我编写GetDisposable (条件是我必须实例化IDisposable对象并运行可能在返回语句之前抛出异常的代码)?
发布于 2010-11-19 08:23:03
根据您想要的GetDisposable语义,我可能会这样实现它:
public static Disposable GetDisposable(bool error)
{
var obj = new Disposable();
try
{
if (error)
throw new Exception("Error!");
return obj;
}
catch (Exception)
{
obj.Dispose();
throw;
}
}发布于 2010-11-19 08:18:17
它永远不会被调用的原因是你分配它的方式。"tmp“变量根本不会被分配,因为由于抛出了一个异常,所以GetDisposable(bool)函数永远不会返回。
如果你说下面这句话,
using (var tmp = new Disposable())
{
throw new ArgumentException("Blah");
}然后,您将看到IDisposable::Dispose()确实被调用了。
要理解的基本内容是,using块必须获得对IDisposable对象的有效引用。如果发生了一些异常,导致在using块中声明的变量没有被赋值,那么您就倒霉了,因为using块将不知道IDisposable对象。
至于从函数返回IDisposable对象,您应该在函数内部使用标准的catch块在失败的情况下调用Dispose(),但显然不应该使用using块,因为这将在您自己准备好之前释放对象。
发布于 2010-11-19 08:23:14
这是因为从未赋值过tmp变量。这是使用一次性对象时需要注意的问题。GewtDisposable更好的定义应该是:
public static Disposable GetDisposable(bool error)
{
var obj = new Disposable();
try
{
if (error)
throw new Exception("Error!");
return obj;
}
catch
{
obj.Dispose();
throw;
}
}因为它确保了obj被释放。
https://stackoverflow.com/questions/4221005
复制相似问题