我还没有在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的错误,此部分已被删除。需要进一步调查
答案 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.MethodThatThrowsAnException()处
在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");
}
未处理的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");
中的原始异常将被捕获并在那里处理。您将不会注意到过滤器方法中先前抛出的异常。