关于C#:在同一个catch块中捕获两个异常?

Catch two exceptions in the same catch block?

我有一个方法可以抛出两个不同的异常:CommuncationExceptionSystemException。在这两种情况下,我都执行相同的三行代码块。

1
2
3
4
5
6
7
8
9
10
11
try {
 ...
}

catch (CommunicationException ce) {
   ...
}

catch {SystemExcetion se) {
   ...
}

有没有可能这样做?

1
2
3
4
5
6
7
try {
   ...
}

catch (CommunicationException ce, SystemException se) {
   ...
}

那我就不用写这么多代码了。我知道我可以将异常处理提取到私有方法中,但是由于代码只有3行长,所以方法定义需要的代码比主体本身要多。


如果你能把你的应用升级到C 6,你就很幸运了。新的C版本实现了异常过滤器。所以你可以这样写:

1
2
3
catch (Exception ex) when (ex is CommunicationException || ex is SystemException) {
    //handle it
}

有些人认为此代码与

1
2
3
4
5
6
catch (Exception ex) {                
    if (ex is CommunicationException || ex is SystemException) {
        //handle it
    }
    throw;
}

但事实并非如此。实际上,这是C 6中唯一不可能在以前版本中模拟的新功能。首先,再掷意味着比跳过捕获更多的开销。第二,它在语义上不是等价的。在调试代码时,新特性会保持堆栈的完整性。如果没有这个特性,崩溃转储就不那么有用,甚至是无用的。

请参阅关于CodePlex的讨论。以及一个显示差异的例子。


实际上,你只能抓到SystemException,它也能处理CommunicationException,因为CommunicationException是从SystemException派生出来的。

1
2
3
catch (SystemException se) {
   ... //this handles both exceptions
}


不幸的是,没有办法。您使用的语法无效,也不可能像switch语句那样执行fall through。我认为你需要使用私人方法。

一个小小的黑客工作是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
var exceptionHandler = new Action<Exception>(e => { /* your three lines */ });
try
{
    // code that throws
}
catch(CommuncationException ex)
{
    exceptionHandler(ex);
}
catch(SystemException ex)
{
    exceptionHandler(ex);
}

你需要自己决定这是否有意义。


不,你不能那样做。我知道的唯一方法是捕获一个泛型异常,然后检查它是什么类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try
{
   ...
}
catch(Exception ex)
{
   if(ex is CommunicationException || ex is SystemException)
   {
      ...
   }
   else
   {
     ... // throw; if you don't want to handle it
   }
}


可能的副本

一次捕获多个异常?

我引用这里的答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
 catch (Exception ex)            
       {                
           if (ex is FormatException ||
               ex is OverflowException)
           {
               WebId = Guid.Empty;
               return;
           }
           else
           {
               throw;
           }
       }


怎么样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try {


...
}

catch (CommunicationException ce) {
   HandleMyError(ce);
}

catch {SystemExcetion se) {
   HandleMyError(se);
}

private void HandleMyError(Exception ex)
{
// handle your error
}


既然您对这两种类型的异常都做了相同的操作,那么您只需执行以下操作:

1
2
3
4
5
6
7
8
try
{
    //do stuff
}
catch(Exception ex)
{
    //normal exception handling here
}

只有在需要为显式异常类型做一些独特的事情时才捕获它。