为什么使用终于在尝试…赶上
我看到Finally
in Try .. Catch
将总是在执行try catch块的任何部分之后执行。
是否有什么不同,只是跳过Finally
一节,只是之后,在try catch块之外运行?
示例1,Try … Catch … Finally … End Try
Try 'Do something Catch ex As Exception 'Handle exception Finally 'Do cleanup End Try
例2,尝试…赶上…结束尝试…做最后的东西外面
Try 'Do something Catch ex As Exception 'Handle exception End Try 'Do cleanup
是的,这是不同的。 最后将永远运行(禁止程序崩溃)。 如果函数在try catch块内部退出,或者在try或catch中引发另一个错误,finally仍然会执行。 你不会使用finally语句来获得这个function。
带有四个单选button的代码:
- 返回TRY
- 在CATCH中返回
- 投入CATCH
-
完成CATCH
private void checkFinally() { try { doFinally(); } catch { Console.WriteLine(" Breaking news: a crash occured. "); } } private void doFinally() { Console.WriteLine(" "); Console.Write("Here goes: " + (radioReturnInTry.Checked ? "2. Return in try: " : (radioReturnInCatch.Checked? "3. Retrun in catch: " : (radioThrowInCatch.Checked? "4. Throw in catch: " : "1. Continue in catch: "))) ); try { if (radioReturnInTry.Checked) { Console.Write(" Returning in try. "); return; } Console.Write(" Throwing up in try. "); throw new Exception("check your checkbox."); } catch (Exception ex) { Console.Write(" ...caughtcha! "); if (radioReturnInCatch.Checked) { Console.Write("Returning in catch. "); return; } if (radioThrowInCatch.Checked) { Console.Write(" Throwing up in catch. "); throw new Exception("after caught"); } } finally { Console.Write(" Finally!!"); } Console.WriteLine(" Done!!!"); // before adding checkboxThrowInCatch, // this would never happen (and was marked grey by ReSharper) }
输出:
- 这里是:1.继续捕获:在尝试中投掷。 … caughtcha! 最后!! 完成!
- 这里是:2.尝试返回:尝试返回。 最后!!
- 这里是:3.在追赶中:在尝试中投掷。 … caughtcha! 回到捕捉。 最后!!
- 在这里:4.投入:尝试投掷。 … caughtcha! 投掷在捕捉。 最后!! 最新消息:发生崩溃。
总结:最后要处理两件事情:
- 在try或catch中返回的代码。
- 或者如果你在尝试中遇到exception,AND THROW在捕获中发生exception,
- 或者,如果您在尝试中遇到了exception,并且不知道该exception,
最后总结一下“最后” :如果你尝试过, 最后没什么特别的
- 没有回报,
- 并在审判期间发现任何exception情况
- 也没有返回在捕捉任何,和
- DID不投掷或有代码抛出。
最后但并非最不重要(最后):如果你的代码中有一个例外,你没有捕获,你的代码将飞,没有达到最后。
希望这是明确的。 (现在是我…)
摩西
最后包含需要在所有条件下进行评估的代码[无论是否发生exception]。
没有办法退出try块而不执行finally块。 如果finally块存在,它总是执行。 (这个语句对于所有的意图和目的都是正确的,有一种方法可以在不执行finally块的情况下退出一个try块,如果代码执行一个System.exit(0);在一个try块内,应用程序终止,另一方面,如果你在try块中拔掉了机器,那么finally也不会执行)。
主要用于处理对象。 当你想closures用户定义的资源时,如文件,打开的资源(db stmts),这将会很有用。
编辑
最后在stackoverflowexception之后也不会执行。
不同之处在于try
块中的代码引发了一个catch
块没有捕获到的exception。
通常情况下, catch
块会捕获特定types的exception,并让其他东西通过。 在这种情况下, finally
块仍然会运行。
如果try
块中的代码return
, finally
块也会运行。
处理数据库连接或任何时候需要处理的对象时,这是个好主意。 为了万一在运行查询时出现问题,您仍然可以安全地closures连接。 它还有助于清理try / catch / finally块之外的块无法访问的代码。
Finally块将执行,无论该函数是否由于exception而退出。 (有这个规则的一些例外, 请参阅此stackoverflow问题的更多信息)。
例如:
Try 'Do something Catch ex As Exception if 'Some Condition throw ex else 'Handle exception Finally 'Do cleanup End Try
在这种情况下,尽pipe你可能抛出一个exception,但Finally块仍然会被执行。
这是一个很好的做法,因为它确保您的清理代码始终执行。 当然使用Resoource Acquisition Is Initialization成语是一种确保资源清理的更简洁的方法,但是我对VB.net不够熟悉,不知道这是否可行。
您最终使用清理代码,例如数据库连接或需要closures的文件。 几乎所有需要执行的清理代码都不考虑exception
此外,您的exception处理可能需要重新抛出exception或其他exception,在这种情况下,块之后的代码将不会执行
在finally块中清理是为了确保它运行。 如果catch块没有处理exception(即它只logging它),甚至导致另一个exception,那么finally块中的代码仍然会运行。
除了其他人所说的,在语义上我认为它们是不同的。
finally块中的代码清楚地表明你正在为try-catch中包含的内容做最终化types的任务。 我认为这使得阅读更清晰。
据我记得,我从来没有在我的.NET代码中使用try / catch / finally块。
一般来说,很less需要在中间层捕获exception。 exception通常会传播到表示层中的顶级处理程序(可能会在层边界捕获并重新生成,以便它们可以被logging)。
所以在中间层,你会经常看到try / finally(或“using”语句),以便清理资源。 然后在表示层的顶级处理程序的try / catch中。
在罕见的情况下,我需要同时捕获一个exception,并进行一些清理,我宁愿重构,以便以下内容:
try { ... do something } catch { ... handle exception } finally { ... cleanup }
变为:
try { DoSomethingAndCleanup(); } catch { ... handle exception } ... private void DoSomethingAndCleanup() { try { ... do something } finally { ... cleanup } }
恕我直言,这是更清洁。
最后,应该用于所有需要完成的工作,以保持系统的一致性。 这通常意味着释放资源
最后总是被执行,不pipe抛出什么exception。 在以下情况下应该使用它来释放资源:
- 完成连接
- closures文件处理程序
- 自由的记忆
- closures数据库连接
让我举一个完整的例子。 想象一下,你正在通过networking发送消息。 在伪代码中:
// With finally | //Without finally try{ | try{ send_message() | send_message() } catch(NetworkError){ | } catch(NetworkError){ deal_with_exception() | deal_with_exception() } finally { | } finalizes_connection() | finalizes_connection() } |
这两个代码的唯一区别是当try
块中保存的内容引发一个不是NetworkError
的exception,例如MethodNotFound
。 在第一种情况下,方法finalizes_connection()
将被调用,而在第二种情况下,它不会。
连接自然是通过多个程序完成的。 那么在另一个程序的MethodNotFound
exception的情况下会发生什么呢? 在第一种情况下,你的程序将完成连接和其他程序,它会很高兴。 在第二种情况下,另一个程序可以永远等待你的回应。 如果其他程序每次只能接收一个连接呢? 你只是窃听了其他程序。
这也适用于一个文件,例如,你打开了,其他程序将无法打开阅读(在Windows中)。 而对于内存,它从来没有释放,现在你有内存泄漏。
执行try catch块的任何部分后,Catch将不会运行。 只有在抛出exception并且catch块可以处理这种types的exception的情况下,Catch 才会运行。
finally块是在try块完成时运行的块。 通过完成,我的意思是它正常结束,或以某种方式退出(跳出循环,从方法返回,抛出exception等)
如果你把代码放在finally块之外,并抛出一个exception(例如),那么如果这个exception没有被捕获,或者在catch块中被重新抛出,或者catch中抛出一个新的exception块。 如果你把它放在finally块中,那么它将被执行。
基本上,清理应该放在最后一块。
在阅读了我上面评论的回复之后,我想到了一些事情。
这个问题基本上不能用完全知道代码的问题来回答。
原因是不是所有的代码都可以放在finally块中。 例如yield语句不允许在最终(和catch)块中。 try块可能有几个执行分支,其中一些返回而另一些则没有。 在所有这些情况下,最终被执行,而在最后的例子中,清理代码并不是这样。 更进一步,你不能跳转(goto)到一个finally块,虽然很less见,你可以跳到catch块后面的代码。 你也不能从finally块返回。
虽然最不常见的情况下,答案取决于实际的代码,但也有不less。
我经常使用的是(我将其封装成一个方面,但是这是我推导的方面):
public static DoLengthyProcessing(this Control control, Action<Control> action) { Cursor oldCursor = control.Cursor try { control.Cursor = Cursors.WaitCursor; action(control); } catch (Exception ex) { ErrorHandler.Current.Handler(ex); } finally { control.Cursor = oldCursor; } }
或者,使用AOP(和我一样)。