通常是的,finally 会运行。
对于以下三种情况,finally 将始终运行:
- 没有异常发生
- 同步异常(正常程序流程中发生的异常)。
这包括派生自 System.Exception 的 CLS 兼容异常和不派生自 System.Exception 的非 CLS 兼容异常。不符合 CLS 的异常由 RuntimeWrappedException 自动包装。C# 不能抛出非 CLS 投诉异常,但 C++ 等语言可以。C# 可能正在调用以一种可以引发不符合 CLS 的异常的语言编写的代码。
- 异步 ThreadAbortException
从 .NET 2.0 开始,ThreadAbortException 将不再阻止 finally 运行。ThreadAbortException 现在被提升到 finally 之前或之后。finally 将始终运行并且不会被线程中止中断,只要在线程中止发生之前实际输入了 try。
以下场景,finally 不会运行:
异步 StackOverflowException。
从 .NET 2.0 开始,堆栈溢出将导致进程终止。finally 不会运行,除非应用进一步的约束以使 finally 成为 CER(受约束的执行区域)。CER 不应用于一般用户代码。它们只应在清理代码始终运行至关重要的情况下使用 - 在所有进程无论如何都会因堆栈溢出而关闭并且因此默认情况下将清理所有托管对象之后。因此,CER 唯一相关的地方是分配在进程之外的资源,例如非托管句柄。
通常,非托管代码在被用户代码使用之前由某个托管类包装。托管包装类通常会使用 SafeHandle 来包装非托管句柄。SafeHandle 实现了一个关键终结器和一个在 CER 中运行的 Release 方法,以保证清理代码的执行。出于这个原因,您不应该看到 CER 散布在整个用户代码中。
因此,finally 不在 StackOverflowException 上运行的事实应该对用户代码没有影响,因为该进程无论如何都会终止。如果您确实需要在 SafeHandle 或 CriticalFinalizerObject 之外清理一些非托管资源的边缘情况,则按如下方式使用 CER;但请注意,这是不好的做法——非托管概念应抽象为托管类和适当的 SafeHandle 设计。
例如,
// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This is *NOT* a CER
}
finally
{
// This is a CER; guaranteed to run, if the try was entered,
// even if a StackOverflowException occurs.
}