如何处理从Dispose抛出的异常?

Mor*_*eng 19 .net dispose idisposable

最近,我正在研究一些关于没有处理的对象的棘手错误.

我在代码中找到了一些模式.据报道,有些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;

}
Run Code Online (Sandbox Code Playgroud)

我怀疑Foo.Dispose可能会抛出异常,因此不会执行以下代码,因此不会释放m_bar.

由于Foo/Bar可能来自第三方,因此不保证不会抛出异常.

如果只使用try-catch包装所有Dispose调用,代码将变得笨拙.

处理这个问题的最佳做法是什么?

Sam*_*ron 30

确实泄露了一个dispose方法的异常是非常糟糕的,特别是因为实现IDisposable的东西通常会指定一个调用Dispose的终结器.

问题是通过处理异常来解决地毯下的问题可能会让您遇到一些非常难以调试的情况.如果您的IDisposable分配了一个仅在处置后才会被释放的关键部分,该怎么办?如果你忽略了异常发生的事实,你可能会陷入死锁中心.我认为Dispose中的失败应该是您希望尽早失败的情况之一,因此您可以在发现错误后立即修复错误.

当然这一切都取决于被处理的对象,对于某些对象,您可能能够恢复,而其他对象则不能.作为一般经验法则,Dispose在正确使用时不应抛出异常,并且您不必在要调用的嵌套Dispose方法中对异常进行防御性编码.

你真的不想在地毯下扫除OutOfMemoryException吗?

如果我有一个狡猾的第三方组件,任意在Dispose上抛出异常,我会修复它并将其托管在一个单独的进程中,我可以在它开始播放时拆除它.


wom*_*omp 7

如果在终结上下文中调用 Dispose() 并抛出异常,则您的进程将终止。

如果您怀疑 Foo.Dispose() 抛出异常,我会尽可能最后处理它,并将其包装在 try/catch 中。尽一切可能在捕获中摆脱它 - 将引用设置为空。从 Dispose() 抛出异常是非常糟糕的,应该避免。

不幸的是,如果这是有问题的第三方代码,最好的办法是让他们修复它。你不应该在它之后手动清理。

希望有帮助。

  • @womp,它输了,如果您隐藏/处理从处置抛出的任意异常,您最终可能会泄漏内存或句柄或操作系统锁。所有这些都会对您的流程造成严重破坏。 (3认同)

noo*_*nex 5

根据设计规则

“IDisposable.Dispose 方法不应引发异常。”

因此,如果您的程序因 Dispose() 未处理的异常而崩溃 - 请参阅官方解决方案