C# 中如何一次 catch 多个异常?

咨询区

  • Michael Stum

在项目开发中当抛出异常时,我会简单的用 System.Exception,但这种会捕获所有的异常,我不希望大一统,我只想捕获我预知的几个异常,然后在这里处理一些特定的业务逻辑。.

目前我只能这么实现,代码如下:

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

上面的两种异常的处理逻辑是一致的,我但重复写了 WebId = Guid.Empty; ,是否有办法可以只写一次呢?

回答区

  • Tamir Vered

最简单的方法就是在 catch 作用域中使用 if 语句, 但在 C#6.0 之后就不需要这么麻烦了,可以直接使用新特性 异常过滤器, 这种特性已经被 CLR 直接支持而不仅仅是 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");
}

值得注意的是:Exception Filters 和 catch 中写 if 有着不同的语义,当第一个 Exception Filters 中的判断条件不满足或者在内部抛出了异常,代码会继续判断下一个 Exception Filters ,参考代码如下。

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

Output: General catch

如果 Exception Filter 有多个 true,那么只会命中第一个。

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

Output: Catch.

如果你观察代码的 IL,你会发现,Exception Filter 并不是多 if 判断的语法糖,而是 MSIL 专门提供的 filter, endfilter  关键词法。

C# 中如何一次 catch 多个异常?

点评区

现代化的 C# 语法糖太多了,Michael Stum 大佬总结的很全面,学习了。