我正在为一位朋友审查一些代码,并说他在try-finally块中使用了一个return语句 . 即使try块的其余部分没有,Finally节中的代码是否仍会触发?
例:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
13 回答
简单回答:是的 .
是 . 这实际上是最终陈述的要点 . 除非发生某些事情(内存不足,计算机未插入等),否则应始终执行finally语句 .
如果你使用System.exit(0)退出应用程序,最后不会运行;如在
结果就是:试试
finally块的主要目的是执行在其中写入的任何内容 . 它不应该依赖于try或catch中发生的任何事情 . 但是对于System.Environment.Exit(1),应用程序将退出而不移动到下一行代码 .
它也不会触发未捕获的异常并在Windows服务中托管的线程中运行
Finally is not executed when in a Thread running in a Windows Service
有一个非常重要的例外,我在其他任何答案中都没有提到过,而且(在用C#编程18年后)我无法相信我不知道 .
如果你在
catch
块中抛出或触发任何类型的异常(不只是奇怪的StackOverflowExceptions
和那种类似的东西),并且你没有整个try/catch/finally
块在另一个try/catch
块中,你的finally
块赢了't execute. This is easily demonstrated - and if I hadn' t我自己看到了鉴于我经常只是非常奇怪的小角落情况会导致finally
块无法执行,我不会相信它 .我这是一个原因,但它并没有广为人知 . (例如,它被注意到here,但在这个特定问题中没有任何地方 . )
我意识到我的例子)确实抛出异常MSDN状态(https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx):_ "If the exception is not caught, execution of the finally block depends 关于操作系统是否选择触发异常展开操作 . “
如果调用堆栈中的某些其他函数(例如Main)捕获异常,则仅保证finally块执行 . 这个细节通常不是问题,因为所有运行时环境(CLR和OS)C#程序都在进程退出时拥有的大多数资源(文件句柄等)上运行 . 在某些情况下,它可能是至关重要的:正在进行的数据库操作正在进行中,您要提交resp . 放松;或某些远程连接,可能无法由操作系统自动关闭,然后阻止服务器 .
这是一个小测试:
结果是:
一般是的,终于会运行 .
对于以下三种情况,最终将始终运行:
No exceptions occur
Synchronous exceptions (正常程序流程中发生的异常) .
这包括从System.Exception和非CLS兼容的异常派生的CLS兼容异常,这些异常不是从System.Exception派生的 . RuntimeWrappedException会自动包装非CLS兼容的异常 . C#不能抛出非CLS投诉异常,但C语言可以 . C#可以调用用可以抛出非CLS兼容异常的语言编写的代码 .
Asynchronous ThreadAbortException
从.NET 2.0开始,ThreadAbortException将不再阻止finally运行 . ThreadAbortException现在被提升到finally之前或之后 . 最终将始终运行并且不会被线程中止中断,只要在线程中止发生之前实际输入了try .
以下场景,终于不会运行:
Asynchronous StackOverflowException.
从.NET 2.0开始,堆栈溢出将导致进程终止 . 除非应用进一步约束以使最终成为CER(约束执行区域),否则最终将不会运行 . CER不应用于一般用户代码 . 它们只应在清理代码始终运行至关重要的地方使用 - 无论如何都要关闭堆栈溢出,因此默认情况下将清理所有托管对象 . 因此,CER应该与之相关的唯一地方是在流程外部分配的资源,例如,非托管句柄 .
通常,非托管代码在被用户代码使用之前由某个托管类包装 . 托管包装器类通常会使用SafeHandle来包装非托管句柄 . SafeHandle实现了一个关键的终结器,以及一个在CER中运行的Release方法,以保证执行清理代码 . 因此,您不应该看到CERs遍布整个用户代码 .
因此,最终不会在StackOverflowException上运行的事实应该对用户代码没有影响,因为该进程无论如何都将终止 . 如果你有一些边缘情况,你需要清理一些非托管资源,在SafeHandle或CriticalFinalizerObject之外,那么使用CER如下;但请注意,这是不好的做法 - 非托管概念应抽象为a托管类和适当的SafeHandle(s)设计 .
例如 . ,
99%的场景将保证
finally
块中的代码将运行,但是,请考虑这种情况:你有一个具有try
- >finally
块(没有catch
)的线程,并且你得到一个未处理的异常线 . 在这种情况下,线程将退出并且不会执行其finally
块(在这种情况下应用程序可以继续运行)这种情况非常罕见,但只是表明答案并非总是“是”,大部分时间都是“是”,有时候,在极少数条件下,“不” .
是的,最后致电 .
引自MSDN
通常,是的 . finally部分保证执行包括异常或return语句在内的任何操作 . 此规则的一个例外是线程上发生异步异常(
OutOfMemoryException
,StackOverflowException
) .要了解有关异步异常和可靠代码的更多信息,请阅读constrained execution regions .