CSharp - 捕获多个异常呢?

  显示原文与译文双语对照的内容

不建议简单地捕获 System.Exception 。 相反,只应该捕获"已知"异常。

现在,这有时会导致unneccessary重复代码,例如:


try
{
 WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
 WebId = Guid.Empty;
}
catch (OverflowException)
{
 WebId = Guid.Empty;
}

我想知道:有一种方法可以捕获这两个异常,只调用 WebId = Guid.Empty 调用一次?

编辑: 所给的示例是相当简单的,因为它只是一个 当向导。 但是,想象一下你多次修改一个对象的代码,如果其中一个操作以预期的方式失败,你想让对象。 但是,如果有一个意外的异常,我仍然想抛出更高的异常。

约了答复谢谢大家 ! 出于某些原因,我在 switch-case 语句上设置了我的思想,它不支持在 GetType() 上切换。 现在,有两个答案,一个使用" typeof",一个使用" is"。 我首先认为 typeof() 是我的函数,因为我认为"嘿,我只想捕捉 FormatException,因为这是我唯一的期望"。 但这不是 catch()的工作方式: catch也捕获所有派生异常。 在考虑它之后,这很明显: 否则,catch(Exception ex) 将无法工作 ! 正确答案是" is"。 是的,只有一个问题,学习了两个问题 o/

时间:

捕获类型上的System.Exception 和 switch


catch (Exception ex) 
{ 
 if (ex is FormatException || ex is OverflowException)
 {
 WebId = Guid.Empty;
 return;
 }

 throw;
}

不在 C# 中,因为你需要一个异常过滤器来执行它,C# 并没有暴露这个特性。 VB.Net 确实有这个功能,e.g.


Catch ex As Exception When TypeOf ex Is FormatException OrElse TypeOf ex Is OverflowException

你可以使用匿名函数来封装on-error代码,然后在那些特定的catch块中调用它:


Action onError = () => WebId = Guid.Empty;
try
{
//something
}
catch (FormatException)
{
 onError();
}
catch (OverflowException)
{
 onError();
}

我知道我现在有点晚了,但是 holy 。。

切削直开始抓,这种重复了一个更早版本的回答,但如果你真的要执行几个异常类型并保持整个事情又干净又整齐的一个常见行为范围内的一个方法,为什么不干脆用一个 lambda/closure/inline 功能像下面这样操作啊? 我的意思是,机会是很好的,你会最终会意识到,你只是想让包合物中一个单独的方法,你可以利用牵制。 又说会变得超级容易做到这一点,而不必实际改变剩下的代码结构上。 对吧?


private void TestMethod ()
{
 Action<Exception> errorHandler = ( ex ) => {
//write to a log, whatever...
 };

 try
 {
//try some stuff
 }
 catch ( FormatException ex ) { errorHandler ( ex ); }
 catch ( OverflowException ex ) { errorHandler ( ex ); }
 catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
}

我不禁想知道( 警告: 有点反讽/讽刺言语的前进) 你到底为什么转到所有这些努力只是简单的替换一行代码。


try
{
//try some stuff
}
catch( FormatException ex ){}
catch( OverflowException ex ){}
catch( ArgumentNullException ex ){}

- - 充满疯狂这种 代码异味 旁边,我期望示例的变体,只是为了假装你正在保存的计算机中窃取信息。


//sorta sucks, let's be honest...
try
{
//try some stuff
}
catch( Exception ex )
{
 if (ex is FormatException ||
 ex is OverflowException ||
 ex is ArgumentNullException)
 {
//write to a log, whatever...
 return;
 }
 throw;
}

因为它当然不是自动的。

当然,我保留了三个相同的实例 /* write to a log, whatever... */return; 在第一个示例中。

但这就是我的观点。 你都听说过函数/方法,对吧? 认真。编写一个通用的ErrorHandler 函数,然后从每个catch块调用它。

如果你问我,第二个示例( 使用 ifis 关键字) 既是明显缺乏可读性,同时又明显更error-prone的维护阶段期间你的项目。

路由维护阶段,对于那些已经可能是相对编程新手,是打算构成 98.7 % 或者多个你的项目,而那可怜的整体寿命schmuck做维护是几乎毫无疑问将是除你之外的。 在对时间作业cursing你name,并有一个很好的机会他们将耗费 50%的自己。

当然还有FxCop中树皮在你,所以你必须 将属性添加到你的代码,数据集正好有拉链是跟 99.9中正在运行的程序的问题,以及有什么,都告诉要忽略FxCop浮现 % 中情况下,它是完全正确的衰退现象。 我很遗憾,我可能会被误认为是,但实际上这都不能"忽略"属性最终会编译到你的应用程序?

将整个 if 测试放在一行中使得它更具可读性? 我不这样认为。我是说,我的确有另一个程序员vehemently论证一旦很久以前,它将更多代码在一行上会使它"运行速度快。"但是当然他是僵硬的胡言乱语螺母。 对着他whatsoever,试图向他说明( 有一个直接的face--which是很有挑战性的) 如何使用解释器或者编译器会那么长的时间线分别放到离散one-instruction-per-line破裂,则它的statements--essentially与结果的如果他已经已经提前只是使代码可读而不是试图out-clever使得compiler--had没有 effect. 但我离题了。

在 now, 少多少可以读这是否得到添加另外三个异常类型时,在一两个月? ( 答案,它得到一条 许多 缺乏可读性) 。

其中一个主要点,真正的格式化就是,现有的点,我们都是看着每天都是文字语言的源代码,使之真的非常对其他人类一眼实际发生了什么时,代码将运行。 因为编译器将源代码转换成完全不同的内容,并且不关心你的代码格式风格。 所以all-on-one-line太糟糕了。

只是说。。


//super sucks...
catch( Exception ex )
{
 if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
 {
//write to a log, whatever...
 return;
 }
 throw;
}

为了完整起见,因为 .NET 4.0 代码可以改写成:


Guid.TryParse(queryString["web"], out WebId);

TryParse 从不抛出异常,如果格式错误,则返回 false,将WebId设置为 Guid.Empty

就像其他人指出的,你可以在catch块中有一个 if 语句来确定发生了什么。 在构建 2014时宣布,C#的下一个版本将支持异常筛选器,因此以下操作:


try { … }
catch (Exception e) when (MyFilter(e))
{
 …
}

然后,MyFilter 方法可以如下所示:


private bool MyFilter(Exception e)
{
 return e is ArgumentNullException || e is FormatException;
}

你现在可以下载 Visual Studio 2015的预览来查看这个。

@Micheal

代码的稍微修改过的版本:


catch (Exception ex)
{
 Type exType = ex.GetType();
 if (exType == typeof(System.FormatException) || 
 exType == typeof(System.OverflowException)
 {
 WebId = Guid.Empty;
 } else {
 throw;
 }
}

字符串比较是丑陋和缓慢的。

接受的答案似乎可以接受,除了 CodeAnalysis/FxCop 会抱怨它正在捕获一个一般异常类型。

此外,"是"运算符可能会略微降低性能。

CA1800: 不要无谓地强制转换 说要作为'运算符改为""考虑测试测试结果',但如果你这样做,你将被单独编写更多的代码比你如着每个异常。

总之,这就是我要做的:


bool exThrown = false;

try
{
//Something
}
catch (FormatException) {
 exThrown = true;
}
catch (OverflowException) {
 exThrown = true;
}

if (exThrown)
{
//Something else
}

这是 matt ( 我觉得这有点干净)的答案变体。。使用方法:


public void TryCatch(...)
{
 try
 {
//something
 return;
 }
 catch (FormatException) {}
 catch (OverflowException) {}

 WebId = Guid.Empty;
}

将引发任何其他异常,代码 WebId = Guid.Empty; 不会被命中。 如果你不想让其他异常崩溃你的程序,只需在其他两个捕获后添加这里选项:


...
catch (Exception)
{
//something, if anything
 return;//only need this if you follow the example I gave and put it all in a method
}

如果你能将你的应用程序升级到 C# 6,你就很幸运了。 新的C# 版本实现了异常筛选器。 这样你就可以写:


catch (Exception ex) when (ex is FormatException || ex is OverflowException) {
 WebId = Guid.Empty;
}

有些人认为这个代码与


catch (Exception ex) { 
 if (ex is FormatException || ex is OverflowException) {
 WebId = Guid.Empty;
 }
 throw;
}

首先,re-throw意味着比跳过捕获更多的开销。 其次,它在语义上不是等价的。 在调试代码时,新功能保持堆栈不变。 没有这个功能,故障转储就会变得无用甚至无用。

在CodePlex上查看关于这个的讨论。 一个示例,展示了


catch (Exception ex)
{
 if (!(
 ex is FormatException ||
 ex is OverflowException))
 {
 throw;
 }
 Console.WriteLine("Hello");
}

...