如果我在Try块中返回一个值,将会在finally语句中编写代码?
我正在复习一些朋友的代码,并说他在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 } }
简单的回答:是的。
通常,是的。 finally节保证执行任何事情,包括exception或返回语句。 此规则的一个例外是在线程上发生asynchronousexception( OutOfMemoryException
, StackOverflowException
)。
要了解更多有关这种情况下asynchronousexception和可靠代码的信息,请阅读有关受限制的执行区域 。
这是一个小testing:
class Class1 { [STAThread] static void Main(string[] args) { Console.WriteLine("before"); Console.WriteLine(test()); Console.WriteLine("after"); } static string test() { try { return "return"; } finally { Console.WriteLine("finally"); } } }
结果是:
before finally return after
从MSDN引用
最后用来保证一个语句代码块的执行,而不pipe前面的try块如何退出 。
一般来说,是的,终于会跑。
对于以下三种情况,finally 总是会运行:
- 没有例外发生
- 同步exception (正常程序stream程中发生的exception)。
这包括从System.Exception派生的与CLS兼容的exception和不从System.Exception派生的非CLS兼容的exception。 不符合CLS的exception由RuntimeWrappedException自动包装。 C#不能抛出非CLS投诉exception,但是像C ++这样的语言可以。 C#可能会调用编写的代码,这种代码可能会抛出不符合CLS的exception。 - asynchronousThreadAbortException
从.NET 2.0开始,ThreadAbortException将不再阻止最终的运行。 ThreadAbortException现在被挂起到finally或之后。 终止将总是运行,不会被线程中止,只要在线程中止发生之前实际inputtry。
以下情况下,终于不会运行:
asynchronousStackOverflowException。
从.NET 2.0开始,堆栈溢出将导致进程终止。 最后将不会运行,除非进一步的约束被应用于最后一个CER(约束执行区)。 CERs不应该用于一般的用户代码。 只有在清理代码始终运行至关重要的地方 – 在所有进程closures堆栈溢出之后,所有被pipe理对象都将被默认清除。 因此,唯一与CER相关的地方是分配给stream程之外的资源,例如非托pipe句柄。
通常情况下,非托pipe代码在被用户代码占用之前被某些托pipe类所包装。 托pipe包装类将通常使用SafeHandle来包装非托pipe句柄。 SafeHandle实现了一个关键的终结器和一个在CER中运行的Release方法,以保证执行清理代码。 出于这个原因,你不应该看到CERs散布在整个用户代码中。
所以终于不能在StackOverflowException运行的事实应该不会影响用户代码,因为进程将终止。 如果您在某种情况下需要清理SafeHandle或CriticalFinalizerObject之外的某些非托pipe资源,请按如下方式使用CER: 但是请注意,这是不好的做法 – 非托pipe概念应该被抽象为托pipe类和适当的SafeHandle(s)。
例如,
// 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. }
我意识到我晚了晚会,但在情况下(不同于OP的例子),确实引发exceptionMSDN声明( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): “如果没有捕获exception,finally块的执行取决于操作系统是否select触发exception展开操作。
只有当某个其他函数(例如Main)进一步调用堆栈捕获exception时,finally块才能保证执行。 这个细节通常不是问题,因为所有运行时环境(CLR和OS)的C#程序都在进程所拥有的免费资源(文件句柄等)上运行。 在某些情况下,它可能是至关重要的:数据库操作一半正在进行,你要提交resp。 放松; 或者某些远程连接不能被OS自动closures,然后阻塞服务器。
是。 这实际上是最后声明的要点。 除非发生一些表情事件(内存不足,计算机拔出等),否则应始终执行finally语句。
如果你使用System.exit(0)从应用程序中退出,最后不会运行。 如在
try { System.out.println("try"); System.exit(0); } finally { System.out.println("finally"); }
结果只是:尝试
如果在Windows服务中托pipe的线程中运行,它也不会触发
最后在Threading.Timer中与Windows Service结合执行
99%的情况下,将保证finally
块内的代码将运行,但是,想想这个场景:你有一个线程,有一个try
– > finally
块(没有catch
),你会得到一个未处理的exception线。 在这种情况下,线程将退出并且其finally
块将不会被执行(在这种情况下应用程序可以继续运行)
这种情况是非常罕见的,但只是表明答案并不总是“是”,大部分时间是“是”,有时在极less数情况下是“否”。
finally块的主要目的是执行里面写的任何东西。 它不应该依赖任何在try或catch中发生的事情。但是通过System.Environment.Exit(1),应用程序将退出而不移动到下一行代码。