Catch two exceptions in the same catch block?
我有一个方法可以抛出两个不同的异常:CommuncationException和SystemException。在这两种情况下,我都执行相同的三行代码块。
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行长,所以方法定义需要的代码比主体本身要多。
- 不管怎样,我不完全确定你是否愿意。难道你不会最终还是写代码来区分例外情况吗——if (ce...) else (se...)。最后,它可能看起来更凌乱。
- 这里也存在类似的问题stackoverflow.com/questions/136035/…但是您将捕获基本的Exception,您仍然需要编写代码来检查CommunicationException或SystemException的派生类型…它比你现有的catch {} catch {}更多,所以不值得麻烦。
- @詹姆斯怀斯曼不,我不需要一个如果/否则,因为这两个例外处理是完全相同的。
如果你能把你的应用升级到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
} |
- +1:在他具体的情况下,这就是我们要走的路。抓得好!
- 是的,这是可能的,但这也是一个好的做法吗?我也会捕获所有其他的子类而不明确地知道它?
- 无论如何都要这样做,因为您已经捕获了SystemException。
- 哦,是的;)我从来没想过。那么,第一次捕获是相当无用的。
- 如果执行的代码完全相同:是的,确实如此。
- 不,这不是一个好的实践,因为它会捕获大量的异常。但正如丹尼尔提到的,如果不是交流,你已经这样做了。例外:)
- 是的,这段代码并不是最好的,因为它捕获各种系统异常,而不仅仅是所需的两个异常。你可能希望所有其他的都不要在这个尝试捕获中被捕获!
不幸的是,没有办法。您使用的语法无效,也不可能像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 );
} |
你需要自己决定这是否有意义。
- 他不想那样做:p
- 是的,他在哪里说的?;-)他只是不想创建私有方法,因为它创建了代码开销。这个开销在我的样本中大大减少了。但不管怎样,我的主要答案是,他就是不能做他想做的事…我没有给他提供一个"解决方案",他在这个问题上已经被驳回了。
- 我知道,只是笑了一下:)
不,你不能那样做。我知道的唯一方法是捕获一个泛型异常,然后检查它是什么类型:
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
}
} |
- 这将更改异常的调用堆栈。不是你想要的。
- 如果我只是在else语句中使用throw,那么这为什么会更改调用堆栈?
- 看看这里:stackoverflow.com/questions/515265/&hellip;
- 非常感谢,我一直认为我应该避免使用throw ex
- 没错,您应该避免使用"throw ex;",但这不是他正在做的,他使用"throw;"保留原始异常信息;
可能的副本
一次捕获多个异常?
我引用这里的答案:
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;
}
} |
- 我不同意那个问题中提供的解决方案,因为我不支持亚历克森的回答。这确实和亚历克森给出的答案一样……
- @丹尼尔:嗯。很高兴知道它改变了调用堆栈,可能不能正常工作。
- 在这个解决方案中,重要的是它重新抛出所有的REST类型异常!
怎么样
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
} |
只有在需要为显式异常类型做一些独特的事情时才捕获它。