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

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

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

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

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


当前回答

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

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

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

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

简而言之,没有。

这引出了下一个问题,

如果我不能在同一个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#9的更新

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

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

注意,我确实找到了一种方法,但这看起来更像是《每日WTF》的素材:

catch (Exception ex)
{
    switch (ex.GetType().Name)
    {
        case "System.FormatException":
        case "System.OverflowException":
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}

这里值得一提。您可以响应多个组合(Exceptionerror和Exception.message)。

当我试图在数据网格中转换控件对象时,我遇到了一个用例场景,其中的内容为TextBox、TextBlock或CheckBox。在这种情况下,返回的异常相同,但消息不同。

try
{
 //do something
}
catch (Exception ex) when (ex.Message.Equals("the_error_message1_here"))
{
//do whatever you like
} 
catch (Exception ex) when (ex.Message.Equals("the_error_message2_here"))
{
//do whatever you like
} 
           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;
                }
           }