双胞胎例外之谜

时间:2008-12-15 15:52:53

标签: c# .net

这是一个有趣的问题。我有一个试图运行一些初始化代码的系统。如果失败,我们会打电话给deinitializer清理所有内容。

因为我们在异常处理中调用了deinitializer,所以我们冒着初始化和取消初始化都会失败的风险,假设现在看来我们必须抛出两个异常。

但是,我们似乎不太可能。那么会发生什么以及代码应该做什么?

      try { /* init code here */ }        
      catch (Exception ex)
      {
         try
         {
            _DeinitializeEngine();
         }
         catch (Exception ex2)
         {
            throw new OCRException("Engine failed to initialize; ALSO failed to deinitialize engine!", ex2);
         }
         finally
         {
            throw new OCRException("Engine failed to initialize; failed to initialize license!", ex);
         }
      }

4 个答案:

答案 0 :(得分:8)

你不应该抛出Finally块。相反,使用InnerException在throw中添加信息。

更新

你需要做的是捕获并重新抛出异常的“历史”,这是通过InnerException完成的。您可以在构建新异常时对其进行编辑。这是我刚才写的代码片段,用于说明我在下面的所有评论中解释的想法。

    static void Main(string[] args)
    {
        try
        {
            principalMethod();
        }
        catch (Exception e)
        {
            Console.WriteLine("Test : " + e.Message);
        }
        Console.Read();
    }

    public static void principalMethod()
    {
        try
        {
            throw new Exception("Primary");
        }
        catch (Exception ex1)
        {
            try
            {
                methodThatCanCrash();
            }
            catch
            {
                throw new Exception("Cannot deinitialize", ex1);
            }
        }
    }

    private static void methodThatCanCrash()
    {
        throw new NotImplementedException();
    }

无需使用双掷和终结。如果你在Console.WriteLine(...)上设置了一个断点。您会注意到您拥有所有异常跟踪。

答案 1 :(得分:1)

如果我理解你的问题,这就是我要做的事情:

try { /* init code here */ }            
catch (Exception ex)
{
    // Passing original exception as inner exception
    Exception ocrex = new OCRException("Engine failed to initialize", ex);

    try
    {
        _DeinitializeEngine();
    }
    catch (Exception ex2)
    {
        // Passing initialization failure as inner exception
        ocrex = new OCRException("Failed to deinitialize engine!", ocrex);            
    }
    throw ocrex;
}

答案 2 :(得分:1)

如果您的清理代码失败并且您无法使应用程序处于干净且已知的状态,我会让异常处理不当(或者使用UnhandledException事件捕获它以进行记录),然后关闭应用程序。

因为如果你不能处理第一个异常,那么抓住第二个异常会有什么意义呢?

答案 3 :(得分:0)

您有两种可能的异常情况:第一种方法失败,另一种方法失败。

您已经定义了自己的异常类。因此,使用RelatedExceptionPriorException属性创建另一个(或扩展第一个)。在第二种情况下抛出异常时,请保存对此属性中第一个异常的引用。

由异常处理程序捕获此异常以确定如何处理第二个异常。