如果Exception过滤器的过滤器抛出异常会发生什么

时间:2015-03-05 13:46:37

标签: c# c#-6.0

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

正如标题所示"如果异常过滤器的过滤器抛出异常会怎样?"。我想真正的答案是"过滤器应该以一种永远不会引发异常的方式编写。",但是我们可以这样说。是否异常发生在捕获本身内?

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

或者

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

编辑:有趣的示例 由于示例所基于的涉及volatileread的错误,此部分已被删除。需要进一步调查

4 个答案:

答案 0 :(得分:14)

如果过滤器中抛出异常,则会以静默方式吞下该异常,并且过滤器会失败。这导致原始例外情况下降catch个案例或最终被重新加速。

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

您可以使用volatileread.com’s C# 6 beta interpreter上的以下代码验证这一点:

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 / catch块中。


更新

由于我在不使用外部try / catch块时不理解volatileread编译器的输出,我自己安装了MS Build Tools 2015(截至本答复的时候仍然使用if,而不是when)并试了一下。事实证明,当不使用外部try / catch时,“原始异常”仍然是导致程序崩溃的原因。所以不是过滤器异常。这似乎是volatile编译器的一个错误。

答案 1 :(得分:4)

您可以尝试here

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

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

Spicy detail(bug):如果通过反射调用包含try-catch的方法,并且when子句抛出异常,那么这个异常将被视为未处理而不是原始异常。更多信息here

答案 2 :(得分:3)

编辑:奇怪似乎是由volatileread中的错误引起的。请参考poke的答案。以下实验不可信任

所以我进行了一些实验,给出了一些有趣的结果,以便对这个问题有所了解。

使用http://volatileread.com/utilitylibrary/snippetcompiler?id=7632

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

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

打印出"过滤处理程序2"

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

}

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

打印出来:

  

未处理的Expecption:System.Exception:MethodThatThrowsAnException
  在Program.Main()

的Program.MethodThatThrowsAnException()处

的另一个有趣的输出
   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");   
    }
  

未处理的Expecption:System.Exception:MethodThatThrowsAnException2   在Program.Main()

的Program.MethodThatThrowsAnException2()处

所以它似乎试图评估第一个捕获,如果它抛出异常它继续下一个捕获。第一个没有失败并且匹配所有条件的catch然后处理异常(BTW是try中最初抛出的类型的异常)。但是,如果抛出错误类型的最后一个catch也会在过滤器部分中引发异常,则会在过滤器中抛出Unhandled Exception类型。

修改 注意:

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

输出:

  

陷入

     

System.Exception:Program.Main()

中的强制异常

如果你将它与第二个输出进行比较......地狱怎么样? 在第二个例子中抛出了MethodThatThrowsAnException但在最后一个例子中#34; Forced Exception"被抓了

答案 3 :(得分:0)

异常过滤器中引发的异常将被忽略,这将导致过滤器失败。

Exception filters是自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块用于该特定异常,但该方法的异常将永远不会将其传递给调用者。来自filter方法的IndexOutOfRangeException将被忽略,并且由于第一行中的原始异常throw new Exception("Forced Exception");未在任何地方处理,程序将因未处理的异常“强制异常”而崩溃。


在您的第一个代码段中,由于您有一个基本Exception的catch块,因此第一行throw new Exception("Forced Exception");中的原始异常将被捕获并在那里处理。您将不会注意到过滤器方法中先前抛出的异常。