如果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。