捕获通用非致命异常

时间:2014-01-06 18:07:15

标签: c# .net exception-handling

传统观点认为我们应该只捕捉到我们期望的特定异常类型:

try
{           
    int.Parse(str); //I am aware of TryParse(), this is just for the sake of example
}
catch (FormatException ex)
{
    Console.WriteLine (ex);
}
catch (OverflowException ex)
{
    Console.WriteLine (ex);
}

然而,有时我们并不关心发生了哪个异常(只要它不是致命的),也许是因为我们只是想让用户知道发生了错误。在这些情况下,我们可以这样做:

try
{           
    Foo();
}
catch (Exception ex)
{
    if (IsCriticalException(ex))
    {
        Environment.FailFast("System Error", ex);
    }

    Console.WriteLine ("Error running Foo: {0}", ex);
}   

其中IsCriticalException可以与System.ClientUtils.IsCriticalException类似地实施。由于以下几个原因,我一般都支持这种方法:

  1. 某些方法可能会抛出许多异常类型,捕获它们可能很麻烦。例如,File.Open可以抛出九种不同类型的异常。
  2. 某些方法可能会抛出未记录的异常。这可能是由于缺少文档,或者是由于某些错误。例如,由于一个模糊的错误,ICommunicationObject.Close实际上可能会抛出ArgumentException。有些方法甚至不能静态地知道它们可以抛出哪些异常,因为它们动态地加载其他模块/插件。据推测,他们可以用他们自己已知的例外情况包装所有这些“外部”例外,但我相信并非所有例外情况都有。
  3. 这种方法的批评者认为方法的例外是其合同的一部分。如果抛出的异常不是本合同的一部分,我们应该假设其状态已损坏。我们还会在方法中发现一个错误(因为我们已经吞下了意外的异常,否则我们就不会发现这个错误)。然后我们可以将这个bug传递给框架的开发人员,这是一个胜利 - 特别是如果那些开发人员在我们公司,所以我们“帮助自己”可以这么说。

    我承认,批评者提出了有效的观点,但我觉得他们有点理想主义。实际上,我认为通用的非致命异常捕获在很多情况下都是有意义的。我有道理吗?

    相关阅读:

1 个答案:

答案 0 :(得分:1)

  

传统观点认为我们应该只捕捉到我们期待的特定异常类型

实际上,我认为你应该抓住那些可以处理的异常。捕获异常只是为了重新抛出它们是没有用的,让这些异常通过你本来可以治愈它是没有意义的。

在上面的例子中,我认为拥有一个catch-all块本来没问题,毕竟不转换该字符串是一个可恢复的错误,无论弹出什么异常(除了OutOfMemoryException,无论如何都无法处理,因为任何尝试处理将使用内存)。