在C#中的catch过滤器(when子句)中引发的异常会怎样?可以追踪到他们吗?

时间:2018-09-26 10:53:15

标签: c#

我正在使用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;
}

我要注意的是,如果在catch(..) when (..)中引发异常,则会跳过整个when(..)块。它会跳到下一个匹配的catch块,并且在检查捕获到的异常对象时,不会发现源自when(..)的异常。

我想知道这是否是预期的行为,以及是否有关于docs / spec的参考,说明在这种情况下会发生什么。跳过整个程序块并丢弃异常似乎很奇怪,因为这会使调试变得非常困难。

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

3 个答案:

答案 0 :(得分:5)

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

  

如果在执行用户过滤的表达式期间发生异常,则该异常将被丢弃,并且过滤器表达式被视为评估为false。

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

答案 1 :(得分:0)

尽管具有C#6功能,但异常过滤器已supported by the CLR since .NET Framework 1.1

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

  

如果在执行用户过滤的过程中发生异常   表达式,该异常将覆盖当前异常。在这   情况下,公共语言运行库放弃了对处理程序的搜索   对于当前异常,try构造的finally块   执行,然后从当前try构造外部开始搜索   新异常的处理程序。

答案 2 :(得分:0)

该异常被吞没且过滤器不匹配(好像它返回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所做的)。 / p>