我可以翻译成中文,问题是:我能执行多个Catch块吗?

27

这有点抽象,但是有没有可能抛出异常并使其进入多个catch块?例如,如果它匹配了一个特定的异常,然后是一个非特定的异常。

catch(Arithmetic exception)
{
  //do stuff
}
catch(Exception exception)
{
  //do stuff
}
6个回答

45

拥有多个不同类型的catch块是完全可以接受的。然而,行为是第一个匹配的块处理异常。

它不会进入两个catch块。第一个匹配异常类型的catch块将处理该特定异常,即使在处理程序中重新抛出该异常也是如此,并且不会处理其他任何异常。一旦异常进入catch块,任何后续的catch块都将被跳过。

为了在两个块中捕获异常,您需要像这样嵌套块:

try
{
     try
     {
        // Do something that throws  ArithmeticException
     }
     catch(ArithmeticException arithException)
     {
        // This handles the thrown exception....

        throw;  // Rethrow so the outer handler sees it too
     }
}
catch (Exception e)
{
   // This gets hit as well, now, since the "inner" block rethrew the exception
}

或者,你可以基于特定类型的异常在通用异常处理程序中进行过滤。


2
嵌套对于简单的一级层次结构可以正常工作,但是如果您有需要运行多个不同异常情况的共享代码,则可能会很快变得丑陋。这并不是反对这种方法,而是观察到它并不总是适当的。 - tvanfosson
@tvanfosson:是的,这就是为什么我还添加了过滤选项。你的选项也非常好。 - Reed Copsey

25

不,无法在单个异常处理块中执行两个catch块中的代码。

我可能会将通用异常块中的代码重构为可以从任何一个catch块调用的形式。

try
{
   // blah blah blah
{
catch(Arithmetic ae)
{
   HandleArithmeticException( ae );
   HandleGenericException( ae );
}
catch(Exception e)
{
  HandleGenericException( e );
}

4

像其他人说的那样,异常将被最具体的catch块捕获。

然而,这引出了我对异常处理的困惑。我希望你可以像下面这样做:

catch (ArgumentNullExcpetion, ArugmentOutOfRangeException ex)
{

}

不必再去做

catch (ArgumentNullExcpetion e)
{
}
catch (ArugmentOutOfRangeException outOfRange)
{
}

我理解反对这种做法的原因,可能是因为不同的异常需要采取不同的处理方式,但有时我希望将它们合并。


1
这两个异常都是从ArgumentException派生的,如果你真的想为它们做同样的事情,只需捕获ArgumentException即可。如果您想仅捕获子异常,则需要使用条件逻辑来过滤(并重新抛出)ArgumentException。您的一般观点是正确的,但这不是最好的例子。也许像ValidationException(模型错误)和SqlException(约束违规)这样的例子更好,因为它们不在同一个层次结构中。 - tvanfosson
2
当你说“异常将被最具体的catch块捕获”时,我不认为你是100%正确的。这也取决于顺序。所以如果你先有一个catch all,所有的东西都会落到它身上,即使在它后面有更具体的东西。 - jon
tvanfosson。干得好。我刚刚即兴编写了这个示例。你说得对,在这种情况下,我可以捕获一般的父异常。但是,是的,我想在一个catch块中捕获多个非相关的异常类型。 - Brad Cunningham
好观点Jon,你是正确的,它是有序依赖的。在一个catch块中使用多个异常的另一个原因是为了消除顺序依赖性。 - Brad Cunningham
@tvanfosson:捕获并重新抛出异常是不好的,尽管在C#中可能不可避免。有许多情况下vb的“Catch When”很有用 - 我想知道为什么C#实现者如此坚定地拒绝实现它? - supercat

2

您不能有多个异常块处理同一个异常。但是您可以捕获通用异常,然后尝试转换为更具体的异常,如下所示:

catch (Exception exception)
{
    var aex = exception as ArithmeticException
    if (aex != null)
    {
        // do stuff specific to this exception type
    }
  // then do general stuff
}

2
如果您使用VB.NET,您可以将算术异常的错误处理程序抽象为一个始终返回false的函数或方法调用。
然后,您可以编写类似以下的内容:
Catch ex as Arithmetic When HandleArithmetic()
Catch ex as Exception

End Try

我并不赞同这种用法,尽管我之前见过在日志记录方面建议使用。我认为 C# 没有相应的语法。


-1

这被称为异常过滤,在C#中不受支持(据说在VB.NET中是可能的)。

一个解决方法是捕获一般异常,然后在catch块中检查异常类型,并在继续执行块的其余部分之前对其进行任何特定处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接