C# 一次捕获多个异常?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/136035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:03:40  来源:igfitidea点击:

Catch multiple exceptions at once?

提问by Michael Stum

It is discouraged to simply catch System.Exception. Instead, only the "known" exceptions should be caught.

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

Now, this sometimes leads to unneccessary repetitive code, for example:

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

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

I wonder: Is there a way to catch both exceptions and only call the WebId = Guid.Emptycall once?

我想知道:有没有办法捕获两个异常并且只WebId = Guid.Empty调用一次?

The given example is rather simple, as it's only a GUID. But imagine code where you modify an object multiple times, and if one of the manipulations fail in an expected way, you want to "reset" the object. However, if there is an unexpected exception, I still want to throw that higher.

给定的示例相当简单,因为它只是一个GUID. 但是想象一下你多次修改一个对象的代码,如果其中一个操作以预期的方式失败,你想“重置” object. 但是,如果出现意外异常,我仍然想将其抛出更高。

采纳答案by Joseph Daigle

Catch System.Exceptionand switch on the types

捕捉System.Exception并开启类型

catch (Exception ex)            
{                
    if (ex is FormatException || ex is OverflowException)
    {
        WebId = Guid.Empty;
        return;
    }

    throw;
}

回答by Michael Stum

Note that I did find one way to do it, but this looks more like material for The Daily WTF:

请注意,我确实找到了一种方法,但这看起来更像是The Daily WTF 的材料:

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

回答by Maurice

How about

怎么样

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

回答by FlySwat

@Micheal

@迈克尔

Slightly revised version of your code:

代码的稍微修改版本:

catch (Exception ex)
{
   Type exType = ex.GetType();
   if (exType == typeof(System.FormatException) || 
       exType == typeof(System.OverflowException)
   {
       WebId = Guid.Empty;
   } else {
      throw;
   }
}

String comparisons are ugly and slow.

字符串比较既丑陋又缓慢。

回答by Greg Beech

Not in C# unfortunately, as you'd need an exception filter to do it and C# doesn't expose that feature of MSIL. VB.NET does have this capability though, e.g.

不幸的是,不在 C# 中,因为您需要一个异常过滤器来执行此操作,而 C# 没有公开 MSIL 的该功能。VB.NET 确实有这种能力,例如

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

What you could do is use an anonymous function to encapsulate your on-error code, and then call it in those specific catch blocks:

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

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

回答by Konstantin Spirin

catch (Exception ex)
{
    if (!(
        ex is FormatException ||
        ex is OverflowException))
    {
        throw;
    }
    Console.WriteLine("Hello");
}

回答by Matt

The accepted answer seems acceptable, except that CodeAnalysis/FxCopwill complain about the fact that it's catching a general exception type.

接受的答案似乎可以接受,除了 CodeAnalysis/ FxCop会抱怨它捕获一般异常类型的事实。

Also, it seems the "is" operator might degrade performance slightly.

此外,似乎“is”运算符可能会略微降低性能。

CA1800: Do not cast unnecessarilysays to "consider testing the result of the 'as' operator instead", but if you do that, you'll be writing more code than if you catch each exception separately.

CA1800:不要强制转换为“考虑测试 'as' 运算符的结果”,但如果这样做,与单独捕获每个异常相比,您将编写更多代码。

Anyhow, here's what I would do:

无论如何,这就是我要做的:

bool exThrown = false;

try
{
    // Something
}
catch (FormatException) {
    exThrown = true;
}
catch (OverflowException) {
    exThrown = true;
}

if (exThrown)
{
    // Something else
}

回答by bsara

This is a variant of Matt's answer (I feel that this is a bit cleaner)...use a method:

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

public void TryCatch(...)
{
    try
    {
       // something
       return;
    }
    catch (FormatException) {}
    catch (OverflowException) {}

    WebId = Guid.Empty;
}

Any other exceptions will be thrown and the code WebId = Guid.Empty;won't be hit. If you don't want other exceptions to crash your program, just add this AFTER the other two catches:

将抛出任何其他异常并且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
}

回答by Athari

For the sake of completeness, since .NET 4.0the code can rewritten as:

为了完整起见,从.NET 4.0 开始,代码可以重写为:

Guid.TryParse(queryString["web"], out WebId);

TryParsenever throws exceptions and returns false if format is wrong, setting WebId to Guid.Empty.

如果格式错误,TryParse从不抛出异常并返回 false,将 WebId 设置为Guid.Empty.



Since C# 7you can avoid introducing a variable on a separate line:

C# 7 开始,您可以避免在单独的行中引入变量:

Guid.TryParse(queryString["web"], out Guid webId);

You can also create methods for parsing returning tuples, which aren't available in .NET Framework yet as of version 4.6:

您还可以创建用于解析返回元组的方法,这些方法在 .NET Framework 4.6 版本中尚不可用:

(bool success, Guid result) TryParseGuid(string input) =>
    (Guid.TryParse(input, out Guid result), result);

And use them like this:

并像这样使用它们:

WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;


Next useless update to this useless answer comes when deconstruction of out-parameters is implemented in C# 12. :)

当在 C# 12 中实现输出参数的解构时,这个无用答案的下一个无用更新就会出现。:)

回答by nawfal

Cautioned and Warned: Yet another kind, functional style.

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

What is in the link doesn't answer your question directly, but it's trivial to extend it to look like:

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

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

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

(Basically provide another empty Catchoverload which returns itself)

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

The bigger question to this is why. I do not think the cost outweighs the gain here :)

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