在异常期间捕获Dispose中的异常

时间:2015-11-20 23:15:38

标签: c# exception using idisposable

想象一下,在C#(在.NET 4.5.x中)中,在实现using的对象周围有IDisposible块。想象一下

  1. 在使用块
  2. 中抛出异常
  3. 调用dispose方法时,会抛出一个额外的异常
  4. 将两个异常传递给全局错误处理程序的最佳方法是什么?

    代码示例:

    class SampleClass : IDisposable
    {
        void doSomething()
        {
            // Imagine that this code is actually doing something
            // Except that it unexpectedly hits an exception
            throw new Exception("Exception A");
        }
    
        void Dispose()
        {
           // Imagine that this code is doing some cleanup
           // Except that it is buggy
           // And throws more exceptions
           throw new Exception("Exception B");
        }
    }
    
    static void Main()
    {
        try
        {
            using(var c = new SampleClass())
            {
                c.doSomething();
            }
        } 
        catch (Exception e)
        {
            // Code that records and reports exceptions
            RecordException(e);
        } 
    }
    

    在上面的示例中,我希望记录Exception AException B的所有详细信息。将两个例外传递给RecordException的最佳方法是什么?

    This article建议SafeUsingBlock分机。这是既定的最佳做法吗?

    修改:在这种情况下我控制并可以重写SampleClassSampleClass.Dispose()

1 个答案:

答案 0 :(得分:1)

如果你控制了Dispose()方法,我建议不惜一切代价使其防错。通常,您应该能够安全地依赖IDisposable s Dispose()

如果这是一个你无法控制的课程,你的try包裹using的建议会起作用,但为了使它更优雅,我可能会做更接近的事情:

try
{
    var c = new SampleClass();
    c.doSomething();
    c.Dispose();
}
catch(Exception e)
{
    RecordException(e);
}

SafeUsingBlock()看起来已经完成了工作,但我不认为这是最佳实践:这是一种解决方法。已确立的最佳做法是使Dispose()方法安全。

此外,如果SampleClass是您无法控制的,请考虑将其包装在也实现IDisposable的façade中,并处理Dispose()方法中的错误,例如

public class SampleClassWrapper : IDisposable
{
    private readonly SampleClass _target;
    public SampleClassWrapper(SampleClass target)
    {
        _target = target;
    }

    public void doSomething()
    {
        _target.doSomething();
    }

    public void Dispose()
    {
        try
        {
            _target.Dispose();
        }
        catch(Exception e)
        {
            RecordException(e);
        }
    }
}

然后,您可以安全地在SampleClassWrapper区块内使用using,而无需担心Dispose()

中的失败