最近,我在研究一些关于object not disposed的棘手bug。
我在代码中发现了一些模式。据报道,一些m_foo没有被释放,而SomeClass的所有实例似乎都已经被释放了。
public class SomeClass: IDisposable
{
void Dispose()
{
if (m_foo != null)
{
m_foo.Dispose();
}
if (m_bar != null)
{
m_bar.Dispose();
}
}
private Foo m_foo;
private Bar m_bar;
}
我怀疑Foo.Dispose可能会抛出异常,因此不会执行以下代码,因此不会释放m_bar。
因为Foo/Bar可能来自第三方,所以不能保证不抛出异常。
如果只使用try-catch包装所有Dispose调用,代码将变得笨拙。
处理此问题的最佳实践是什么?
发布于 2009-06-23 03:18:30
如果在finalization上下文中调用Dispose()并抛出异常,您的进程将被终止。
如果您怀疑Foo.Dispose()抛出了一个异常,我会尽可能最后处理它,并将它包装在try/catch中。尽你所能在catch中摆脱它--将reference设置为null。从Dispose()抛出异常是非常糟糕的,应该避免。
不幸的是,如果这是有bet的第三方代码,你最好的办法就是让他们来修复它。你不应该在它之后手动清理它。
希望这能有所帮助。
发布于 2009-10-24 14:46:22
因为你不必在using()语句中分配变量--为什么不使用'stacked‘using语句呢?
void Dispose()
{
// the example in the question didn't use the full protected Dispose(bool) pattern
// but most code should have if (!disposed) { if (disposing) { ...
using (m_foo)
using (m_bar)
{
// no work, using statements will check null
// and call Dispose() on each object
}
m_bar = null;
m_foo = null;
}
“堆叠”using语句的扩展如下:
using (m_foo)
{
using (m_bar) { /* do nothing but call Dispose */ }
}
因此Dispose()调用被放在单独的finally块中:
try {
try { // do nothing but call Dispose
}
finally {
if (m_bar != null)
m_bar.Dispose();
}
finally {
if (m_foo != null)
m_foo.Dispose();
}
我很难在一个地方找到这方面的参考资料。“堆叠的”using语句可以在old Joe Duffy blog post中找到(参见“C#和VB Using语句,C++堆栈语义”一节)。IDisposable上的许多StackOverflow answers都引用了Joe Duffy的帖子。我还发现了一个recent question,其中使用局部变量语句进行堆叠似乎很常见。除了C# language spec之外,我找不到finally块的链接( C# 3.0规范中的8.13节),并且只能在一个'using‘块中找到多个变量,这并不是我所建议的,但是如果你破坏IL,你会发现try/finally块是嵌套的。在null检查中,同样来自C#规范:“如果获取了null资源,则不会调用Dispose,也不会抛出任何异常。”
发布于 2016-08-21 02:45:18
在我的例子中,这是因为一个线程在关闭窗体时访问UI元素。我通过中止form close上的线程重新解决了这个问题。("FormClosing“事件)
FormClosing += (o, e) => worker.Abort();
https://stackoverflow.com/questions/1030455
复制相似问题