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

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

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

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

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


当前回答

C#9的更新

使用C#9中的新模式匹配增强功能,可以缩短异常过滤器中的表达式。现在,捕获多个异常很简单,如下所示:

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

其他回答

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

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
}
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#开发人员最终面临的一个经典问题。

让我把你的问题分成两个问题。第一,

我可以一次捕获多个异常吗?

简而言之,没有。

这引出了下一个问题,

如果我不能在同一个catch()块中捕获多个异常类型,如何避免编写重复代码?

给定您的特定示例,其中回退值构建起来很便宜,我喜欢遵循以下步骤:

将WebId初始化为回退值。在临时变量中构造新的Guid。将WebId设置为完全构造的临时变量。将此作为try{}块的最终语句。

所以代码看起来像:

try
{
    WebId = Guid.Empty;
    Guid newGuid = new Guid(queryString["web"]);
    // More initialization code goes here like 
    // newGuid.x = y;
    WebId = newGuid;
}
catch (FormatException) {}
catch (OverflowException) {}

如果引发任何异常,则WebId永远不会设置为半构造值,并且保持Guid.Empty。

如果构造回退值很昂贵,而重置一个值要便宜得多,那么我会将重置代码移动到它自己的函数中:

try
{
    WebId = new Guid(queryString["web"]);
    // More initialization code goes here.
}
catch (FormatException) {
    Reset(WebId);
}
catch (OverflowException) {
    Reset(WebId);
}

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

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

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

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

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

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

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