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

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

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

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

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


当前回答

           try
           {
                WebId = new Guid(queryString["web"]);
           }
           catch (Exception ex)
           {
                string ExpTyp = ex.GetType().Name;
                if (ExpTyp == "FormatException")
                {
                     WebId = Guid.Empty;
                }
                else if (ExpTyp == "OverflowException")
                {
                     WebId = Guid.Empty;
                }
           }

其他回答

如果你能将你的应用程序升级到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;
}

但事实并非如此。实际上,这是C#6中唯一一个在以前版本中无法模拟的新特性。首先,重投比跳投意味着更多的开销。其次,它在语义上并不等价。当您调试代码时,新功能会保持堆栈的完整性。如果没有这个功能,崩溃转储就没有什么用处,甚至没有什么用处。

请在CodePlexNo available上查看有关此的讨论。以及一个显示差异的示例。

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

or

catch (Exception ex)
{
    if (ex is not FormatException and not OverflowException)
        throw;

    WebId = Guid.Empty;
}

在C#6中,推荐的方法是使用异常过滤器,下面是一个示例:

 try
 {
      throw new OverflowException();
 }
 catch(Exception e ) when ((e is DivideByZeroException) || (e is OverflowException))
 {
       // this will execute iff e is DividedByZeroEx or OverflowEx
       Console.WriteLine("E");
 }

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

因此,您的代码归结为:

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); 
}

不幸的是,在C#中没有,因为您需要一个异常过滤器来实现它,而且C#没有公开MSIL的这一特性。VB.NET确实具有此功能,例如。

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

您可以做的是使用匿名函数封装错误代码,然后在这些特定的catch块中调用它:

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