C# 如果异常过滤器的过滤器抛出异常,会发生什么

C# 如果异常过滤器的过滤器抛出异常,会发生什么,c#,c#-6.0,C#,C# 6.0,我还没有在C#6工作过,但我想知道 正如标题所说,“如果异常过滤器的过滤器抛出异常,会发生什么?”。我想真正的答案是“过滤器应该以这样一种方式编写,它永远不会抛出异常。”,但让我们说它确实如此。异常是否会发生在捕获本身内部 try { throw new Exception("Forced Exception"); } catch (Exception ex) when (MethodThatThrowsAnException()) { WriteLine("Filtered handl

我还没有在C#6工作过,但我想知道

正如标题所说,“如果异常过滤器的过滤器抛出异常,会发生什么?”。我想真正的答案是“过滤器应该以这样一种方式编写,它永远不会抛出异常。”,但让我们说它确实如此。异常是否会发生在捕获本身内部

try
{
  throw new Exception("Forced Exception");
}
catch (Exception ex) when (MethodThatThrowsAnException())
{
  WriteLine("Filtered handler 1");
}
catch (Exception ex)
{
  WriteLine("Filtered handler 2");
}


编辑:有趣的示例 此部分已删除,因为该示例所基于的VolatireRead中存在一个bug。需要进一步调查

您可以尝试一下

正如@Habib正确指出的那样,过滤器只是被跳过,就好像它从未存在过一样。从那时起,catch子句就一直起作用。上面的例子说明了这一点

但是,如果将第二个catch子句更改为无法捕获从方法中抛出的任何内容的类型,则程序将因未处理的异常而崩溃


Spicle detail(bug):如果通过反射调用包含try-catch的方法,并且当子句引发异常时调用一个
,则认为该异常未处理,而不是原始异常。更多信息。

编辑:这种奇怪的现象似乎是由volatieread中的一个bug引起的。请参考poke的回答。下面的实验不可信

因此,我做了一些实验,得出了一些有趣的结果来阐明这个问题

检查使用

打印出“过滤处理程序2”

打印出:

未处理的Expection:System.Exception:MethodThrowsanException
在Program.methodThrowsanException()在Program.Main()处

另一个有趣的输出

   public void Main()
    {
      try
      {
        throw new Exception("Forced Exception");
      }
      catch (Exception ex) when(MethodThatThrowsAnException())
      {
        Console.WriteLine("Filtered handler 1");
      }
      catch (Exception ex) when(MethodThatThrowsAnException2())
      {
        Console.WriteLine("Filtered handler 2");

      }
    }

    private bool MethodThatThrowsAnException()
    {
      throw new Exception("MethodThatThrowsAnException");   
    }

    private bool MethodThatThrowsAnException2()
    {
      throw new Exception("MethodThatThrowsAnException2");   
    }
未处理的Expection:System.Exception:MethodThrowsanException2 在Program.methodThrowsanException2()在Program.Main()处

因此,它似乎试图评估第一个捕获,如果抛出异常,它将继续执行下一个捕获。第一个未失败且匹配所有条件的捕获然后处理异常(顺便说一句,是try中最初抛出的类型的异常)。但是,如果属于抛出错误类型的最后一个捕获也在筛选器部分抛出异常,则将在筛选器中抛出该类型的未处理异常。

编辑: 注:

产出:

抓住

System.Exception:程序.Main()处的强制异常


如果将其与第二个输出进行比较。。。这怎么可能呢?
在第二个示例方法中,通过抛出异常,但在最后一个示例中捕获“强制异常”

如果在筛选器中抛出异常,则该异常将被静默吞没,筛选器将失败。这会导致原始异常在
捕获
案例中向下移动,或最终重新向上移动

因此,调用过滤器的代码无法知道过滤器方法中实际上存在异常。因此,避免抛出异常的情况非常重要,以确保过滤器不会因此而失败

您可以在上使用以下代码进行验证:

这将导致“原始异常”出现在外部try/catch块中


更新
由于我在不使用外部try/catch块时无法理解volatireAD编译器的输出,因此我自己安装了MS Build Tools 2015(截至回答时,它仍然使用
if
,而不是
when
),并进行了尝试。事实证明,当不使用外部try/catch时,“原始异常”仍然是导致程序崩溃的异常。因此,这不是过滤器异常。这似乎是volatile编译器的错误。

异常筛选器中引发的异常将被忽略,并将导致筛选器失败

是自v1.0以来CLR的功能。在VB.Net和F#之前,它们就可以使用了就过滤方法中的吞咽/忽略异常而言,这也是一种已定义的行为,在最近的将来不太可能改变


原始异常将向下移动到其他捕获块,或者在未被任何捕获块捕获的情况下保持未处理状态

考虑以下代码示例:

try
{
    throw new Exception("Forced Exception");
}
catch (Exception ex) if (MethodThatThrowsAnException())
{
    WriteLine("Filtered handler 1");
}
catch (IndexOutOfRangeException ex)
{
    WriteLine("Index Out of Range");
}
方法是:

static bool MethodThatThrowsAnException()
{
    throw new IndexOutOfRangeException("Index Out of Range");
}
尽管该方法正在抛出
IndexOutOfRangeException
,并且在调用方代码中有一个
catch
块用于该特定异常,但该方法的异常永远不会到达调用方<将忽略来自筛选器方法的code>IndexOutOfRangeException
,因为原始异常
抛出新异常(“强制异常”)从第一行开始,没有在任何地方处理,程序将因未处理的异常“强制异常”而崩溃


在您的第一个代码段中,由于您有一个用于基本
异常的catch块
,因此第一行
中的原始异常会抛出新异常(“强制异常”)将在此处捕获并处理。您不会注意到前面在filter方法中抛出的异常



某种程度上说明了为什么Hejlsberg直到现在还不想包括异常过滤器。@PanagiotisKanavos也许他只是不再参与了。C#6有一些可疑的功能,看起来球队不再安全了。这个版本并没有让人想起安德斯。在一个大约48分钟开始的DotNetRocks中提到了这一点——基本上是Mads说安德斯说(意译)“我必须做什么,这样我就再也不用谈论他们了?”-大约49:30。@usr此版本为即将到来的功能攻击-模式匹配等奠定了基础。这是一项巨大的工作,但只有“少数”可见功能。毫无疑问,它们的目的在功能上下文中变得清晰。我的volat理论
   public void Main()
    {
      try
      {
        throw new Exception("Forced Exception");
      }
      catch (Exception ex) when(MethodThatThrowsAnException())
      {
        Console.WriteLine("Filtered handler 1");
      }
      catch (Exception ex) when(MethodThatThrowsAnException2())
      {
        Console.WriteLine("Filtered handler 2");

      }
    }

    private bool MethodThatThrowsAnException()
    {
      throw new Exception("MethodThatThrowsAnException");   
    }

    private bool MethodThatThrowsAnException2()
    {
      throw new Exception("MethodThatThrowsAnException2");   
    }
public void Main()
{
  try
  {
    try
    {
      throw new Exception("Forced Exception");
    }
    catch (Exception ex) when (MethodThatThrowsAnException())
    {
      Console.WriteLine("Filtered handler 1");
    }
  }
  catch (Exception ex)
  {
      Console.WriteLine("Caught");
      Console.WriteLine(ex);
  }
}

private bool MethodThatThrowsAnException()
{
  throw new Exception("MethodThatThrowsAnException");   
}
public void Main ()
{
    try
    {
        try
        {
            throw new Exception("Original exception");
        }
        catch (Exception ex)
            when (Test()) // `if (Test())` in older previews
        {
            Console.WriteLine("Caught the exception");
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}

public static bool Test ()
{
    throw new Exception("Exception in filter condition");
}
try
{
    throw new Exception("Forced Exception");
}
catch (Exception ex) if (MethodThatThrowsAnException())
{
    WriteLine("Filtered handler 1");
}
catch (IndexOutOfRangeException ex)
{
    WriteLine("Index Out of Range");
}
static bool MethodThatThrowsAnException()
{
    throw new IndexOutOfRangeException("Index Out of Range");
}