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

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

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

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

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


当前回答

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

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

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

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

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

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

其他回答

如果你能将你的应用程序升级到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上查看有关此的讨论。以及一个显示差异的示例。

在c#6.0中,异常过滤器是对异常处理的改进

try
{
    DoSomeHttpRequest();
}
catch (System.Web.HttpException e)
{
    switch (e.GetHttpCode())
    {
        case 400:
            WriteLine("Bad Request");
        case 500:
            WriteLine("Internal Server Error");
        default:
            WriteLine("Generic Error");
    }
}

如果您不想在catch范围内使用If语句,在C#6.0中,您可以使用CLR在预览版本中已经支持但仅存在于VB.NET/MSIL中的异常过滤器语法:

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

只有当异常为InvalidDataException或ArgumentNullException时,此代码才会捕获该异常。

实际上,你可以在when子句中放入基本上任何条件:

static int a = 8;

...

catch (Exception exception) when (exception is InvalidDataException && a == 8)
{
    Console.WriteLine("Catch");
}

请注意,与catch范围内的if语句不同,异常过滤器不能抛出异常,当抛出异常时,或者当条件不为真时,将计算下一个catch条件:

static int a = 7;

static int b = 0;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}

输出:常规捕获。

当存在多个真正的异常筛选器时,将接受第一个:

static int a = 8;

static int b = 4;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}

输出:捕获。

正如您在MSIL中看到的,代码不是转换为if语句,而是转换为筛选器,并且异常不能从标记为筛选器1和筛选器2的区域中抛出,但是抛出异常的筛选器将失败,在endfilter命令之前推送到堆栈的最后一个比较值也将决定过滤器的成功/失败(Catch 1 XOR Catch 2将相应地执行):

此外,特别是Guid具有Guid.TryParse方法。

怎么样

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

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

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

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

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

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

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