我见过这个例子:
static void Main(string[] args)
{
Console.WriteLine("Start");
try
{
SomeOperation();
}
catch (Exception) when (EvaluatesTo())
{
Console.WriteLine("Catch");
}
finally
{
Console.WriteLine("Outer Finally");
}
}
private static bool EvaluatesTo()
{
Console.WriteLine($"EvaluatesTo: {Flag}");
return true;
}
private static void SomeOperation()
{
try
{
Flag = true;
throw new Exception("Boom");
}
finally
{
Flag = false;
Console.WriteLine("Inner Finally");
}
}
产生下一个输出:
Start
EvaluatesTo: True
Inner Finally
Catch
Outer Finally
这对我来说听起来很奇怪,我正在寻找对这个命令的一个很好的解释,将它包含在我脑海中。我希望在finally
之前执行when
块:
Start
Inner Finally
EvaluatesTo: True
Catch
Outer Finally
文档说明这个执行顺序是正确的,但它没有详细说明为什么这样做,以及执行顺序的确切规则是什么。
答案 0 :(得分:38)
您可能已经被告知,在发生异常处理时,会分别考虑每种方法。也就是说,由于您的内部方法有try...finally
,因此任何异常都会首先触发finally
,然后它会"看起来"为try
更高。这不是真的。
来自ECR的CLR规范(ECMA-335,I.12.4.2.5异常处理概述):
发生异常时,CLI会在数组中搜索
的第一个受保护块
- 保护包含当前指令指针和
的区域- 是一个catch处理程序块和
- 谁的过滤器希望处理异常
如果在当前方法中找不到匹配项,则搜索调用方法,依此类推。如果未找到匹配项,CLI将转储堆栈跟踪并中止该程序。
如果找到匹配项,CLI会将堆栈移回到刚刚找到的位置,但这次调用finally和fault处理程序。然后它启动相应的异常处理程序。
如您所见,该行为100%符合规范。
try
SomeOperation
try
Main
finally
SomeOperation
finally
中的Main
当然不是其中的一部分 - 它会在执行离开受保护的块时执行,而不管异常。
修改强>
只是为了完整 - 这一直是这样的。唯一改变的是C#现在支持异常过滤器,它允许您观察执行的顺序。 VB.NET支持版本1的异常过滤器。
答案 1 :(得分:-5)
无论是否抛出异常,finally
块始终都会执行。
finally块执行:
唯一可以击败finally块的东西是无限循环或突然发送的进程。 finally块有助于为程序添加确定性