在 C# 中,在 catch 筛选器(when 子句)内引发的异常会发生什么情况?他们能被追踪吗?



我正在使用 C# 中的catch(..) when (..)阅读过滤器表达式,但我找不到任何关于如果在计算表达式时引发异常会发生什么的提及。我尝试浏览文档和规范,但要么找不到它们,要么没有提到它们。所以,我编了一个小程序来检查当我从when(..)扔出去时会发生什么。我把它放在 https://dotnetfiddle.net/R7oJNp

try {
Console.WriteLine("Test(): Inside Test()");
throw new Exception("thrown from Test()");
} catch (Exception) when (AlwaysThrow()) {
Console.WriteLine("Test(): caught exception in Test()");
} catch (Exception e) {
Console.WriteLine("Test(): totally skipped last catch clause, any inner exception: " + (e.InnerException?.Message ?? "nothing"));
throw;
}

我注意到的是,如果在when(..)中抛出异常,则会跳过整个catch(..) when (..)块。它会跳到下一个匹配的catch块,在检查捕获的异常对象时,没有源自when(..)的异常的痕迹。

我想知道这是否是预期的行为,以及是否有关于在这种情况下应该发生的情况的文档/规范的引用。跳过整个块并丢弃异常似乎很奇怪,因为这会使调试变得非常困难。

**编辑:**好的,这是根据.NET文档的行为,但是有什么方法可以跟踪这些吗?我的想法是,异常不能发生,过滤器应该足够简单,但我们会犯错误。另外,这种行为不应该在 C# 规范中提到吗?

VB.Net 早在 C# 之前就支持此功能,因此您可能搜索范围太窄:

如果在执行用户筛选的表达式期间发生异常,则会丢弃该异常,并将筛选器表达式的计算结果视为 false。

https://learn.microsoft.com/en-us/dotnet/standard/exceptions/using-user-filtered-exception-handlers

尽管是 C# 6 功能,但自 .NET Framework 1.1 以来,CLR 一直支持异常筛选器。

表达式中的异常处理方式如下:

如果在执行用户筛选期间发生异常 表达式,则该异常将覆盖当前异常。在此 在这种情况下,公共语言运行库放弃对处理程序的搜索 对于当前异常,try 构造的 finally 块 执行,并在当前 try 构造之外开始搜索 新异常的处理程序。

异常被吞噬,过滤器不匹配(好像它返回了 false(:

void Main()
{
UseFilterThenCatch();
UseFilterOnly();
}
public static bool BadFilter() => throw new Exception("This will be thrown by the filter");
public static void UseFilterThenCatch()
{
try
{
throw new Exception("The exception to catch.");
}
catch(Exception) when (BadFilter())
{
Console.WriteLine("Filtered");
}
catch(Exception e)
{
Console.WriteLine("Unfiltered"); // This line gets hit.
Console.WriteLine(e.Message); // This proves it's the first exception thrown.
}
}
public static void UseFilterOnly()
{
try
{
try
{
throw new Exception("The exception to catch.");
}
catch (Exception) when (BadFilter())
{
Console.WriteLine("Filtered");
}
}
catch(Exception e)
{
Console.WriteLine("Outer catch");
Console.WriteLine(e.Message); // This proves it's the first exception thrown.
}
}

虽然这是特定于语言的,并且 .NET 语言可以执行其他操作,但它是筛选器在 CLR 中的工作方式的重要组成部分,因此这是最自然的相应 CIL 将执行的操作。同样的事情也发生在 VB.NET 和 Linq 表达式上(在解释表达式的情况下需要一些刻意的工作,但在编译表达式中很容易发生,因为它也是最自然的相应 CIL 所做的(。

相关内容

最新更新