不鼓励只捕获System.Exception。相反,只应捕获“已知”异常。

现在,这有时会导致不必要的重复代码,例如:

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

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

给定的示例相当简单,因为它只是一个GUID。但是想象一下,在代码中,您多次修改一个对象,如果其中一个操作预期失败,您希望“重置”该对象。然而,如果有意外的异常,我仍然想把它推得更高。


当前回答

怎么样

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

其他回答

异常过滤器现在在c#6+中可用。你可以的

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

在C#7.0+中,您也可以将其与模式匹配相结合

try
{
   await Task.WaitAll(tasks);
}
catch (Exception ex) when( ex is AggregateException ae &&
                           ae.InnerExceptions.Count > tasks.Count/2)
{
   //More than half of the tasks failed maybe..? 
}

约瑟夫·戴格尔的答案是一个很好的解决方案,但我发现下面的结构更整洁,更不容易出错。

catch(Exception ex)
{   
    if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

反转表达式有几个优点:

return语句不是必需的代码未嵌套不存在忘记“抛出”或“返回”语句的风险,这些语句在Joseph的解决方案中与表达式分离。

它甚至可以压缩成一行(虽然不是很漂亮)

catch(Exception ex) { if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

编辑:C#6.0中的异常过滤将使语法更加简洁,并比任何当前解决方案都有许多其他好处。(最值得注意的是,未损坏堆栈)

下面是使用C#6.0语法时相同问题的外观:

catch(Exception ex) when (ex is SomeException || ex is OtherException)
{
    // Handle exception
}

警告和警告:另一种功能性风格。

链接中的内容不会直接回答您的问题,但将其扩展为以下内容很简单:

static void Main() 
{ 
    Action body = () => { ...your code... };

    body.Catch<InvalidOperationException>() 
        .Catch<BadCodeException>() 
        .Catch<AnotherException>(ex => { ...handler... })(); 
}

(基本上提供另一个返回自身的空Catch重载)

更大的问题是为什么。我不认为这里的成本大于收益:)

想在这条已经很长的线索上加上我的简短回答。还没有提到的是catch语句的优先顺序,更具体地说,您需要了解您试图捕获的每种类型的异常的范围。

例如,如果您使用“catch-all”异常作为异常,它将优先于所有其他catch语句,您显然会遇到编译器错误。但是,如果您颠倒了catch语句的顺序(我认为这有点反模式),您可以将catch-allException类型放在底部,这将捕获任何在尝试中不适合更高级别的异常。。捕捉块:

            try
            {
                // do some work here
            }
            catch (WebException ex)
            {
                // catch a web excpetion
            }
            catch (ArgumentException ex)
            {
                // do some stuff
            }
            catch (Exception ex)
            {
                // you should really surface your errors but this is for example only
                throw new Exception("An error occurred: " + ex.Message);
            }

我强烈建议大家阅读此MSDN文档:

异常层次结构

所以你在每个异常开关中重复了很多代码?听起来提取一个方法是个好主意,不是吗?

因此,您的代码归结为:

MyClass instance;
try { instance = ... }
catch(Exception1 e) { Reset(instance); }
catch(Exception2 e) { Reset(instance); }
catch(Exception) { throw; }

void Reset(MyClass instance) { /* reset the state of the instance */ }

我想知道为什么没有人注意到代码重复。

从C#6中,您还可以使用其他人已经提到的异常过滤器。因此,您可以将上面的代码修改为:

try { ... }
catch(Exception e) when(e is Exception1 || e is Exception2)
{ 
    Reset(instance); 
}