如果Exceptionfilter的filter抛出exception会发生什么

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

正如标题所说“如果Exceptionfilter的filter抛出exception会发生什么?”。 我想真正的答案是“filter应该以一种永远不会抛出exception的方式编写。”但是我们可以这样说。 是否exception发生在捕获本身内?

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的错误,此部分已被删除。 需要进一步调查

如果在filter中抛出exception,则会以静默方式吞下该exception,并且filter会失败。 这会导致原始exception进入catch案例或最终被重新加速。

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

您可以使用volatileread.com的C#6 beta解释器上的以下代码validation这一点:

 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块中出现“原始exception”


更新

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

你可以在这里试一试。

正如@Habib正确指出的那样,filter只是被跳过,就像它从未存在过一样。 从那时起,catch子句就像往常一样工作。 上面的例子certificate了这一点。

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

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

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

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

请使用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(); } 

打印出“Filtered handler 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.Main()中的Program.MethodThatThrowsAnException2()的System.Exception:MethodThatThrowsAnException2

所以它似乎试图评估第一个捕获,如果它抛出exception它继续下一个捕获。 第一个没有失败并匹配所有条件的catch然后处理exception(BTW是try中最初抛出的类型的exception)。 但是,如果抛出错误类型的最后一个catch也会在filter部分中引发exception,则会在filter中抛出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()的强制exception

如果你将它与第二个输出进行比较……地狱怎么样? 在第二个示例中抛出了MethodThatThrowsAnException,但在最后一个示例中,“Forced Exception”被捕获

exceptionfilter中引发的exception将被忽略,它将导致filter失败。

从v1.0开始, exceptionfilter是CLR的特性。 它们可以通过VB.Net和F#获得。 就吞咽/忽略过滤方法中的exception而言,这也是一种定义的行为,并且在最近的将来不太可能改变。


原始exception将向下移动到其他catch块,或者在未被任何捕获的情况下仍未处理。

请考虑以下代码示例:

 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并且调用者代码中存在针对该特定exception的catch块,但该方法的exception永远不会将其传递给调用者。 来自filter方法的IndexOutOfRangeException将被忽略,因为原始exception会throw new Exception("Forced Exception"); 从第一行开始不在任何地方处理,程序将因为Unhandled Exception“Forced Exception”而崩溃。


在你的第一个代码片段中,由于你有一个基本Exception的catch块,你从第一行的原始exception会throw new Exception("Forced Exception"); 将被抓住并在那里处理。 您将不会注意到filter方法中先前抛出的exception。