我几乎肯定答案是肯定的。如果我使用Try Finally块但不使用Catch块,那么任何异常都会冒泡。正确的吗?
对这种做法有何看法?
赛斯
答案 0 :(得分:114)
是的,绝对会。假设你的finally
块没有抛出异常,当然,在这种情况下,它会有效地“替换”最初抛出的异常。
答案 1 :(得分:56)
对这种做法有何看法?
是。 小心。当您的finally块正在运行时,它完全可能正在运行,因为已抛出未处理的意外异常。这意味着某些东西已破坏,并且可能会发生完全意外的。
在这种情况下,可以说你不应该在finally块中运行代码。 finally块中的代码可以构建为假设它所依赖的子系统是健康的,而实际上它们可能会被彻底破坏。 finally块中的代码可能会使事情变得更糟。
例如,我经常看到这样的事情:
DisableAccessToTheResource();
try
{
DoSomethingToTheResource();
}
finally
{
EnableAccessToTheResource();
}
这段代码的作者正在思考“我正在对世界状态进行临时变异;我需要将状态恢复到我被召唤之前的状态”。但是让我们考虑一下这可能出错的所有方法。
首先,调用者已经可以禁止访问资源;在这种情况下,此代码可能会过早地重新启用它。
其次,如果DoSomethingToTheResource抛出异常,那么启用对资源的访问是正确的做法吗?管理资源的代码意外损坏。这段代码说,实际上“如果管理代码被破坏,确保其他代码可以尽快调用那些损坏的代码,这样它也可能会非常失败。”这似乎是一个坏主意。
第三,如果DoSomethingToTheResource抛出异常,那么我们怎么知道EnableAccessToTheResource也不会抛出异常?无论可怕的是什么,资源的使用也可能影响清理代码,在这种情况下,原始异常将丢失,并且问题将更难以诊断。
我倾向于在不使用try-finally块的情况下编写这样的代码:
bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
EnableAccessToTheResource();
现在除非需要,否则状态不会发生变异。现在呼叫者的状态并没有被搞乱。现在,如果DoSomethingToTheResource失败,那么我们就不会重新启用访问权限。我们假设某些事情已经被彻底打破,并且不会冒险通过尝试继续运行代码来使情况变得更糟。如果可以,让呼叫者处理问题。
那么什么时候运行finally块是个好主意?首先,当预期异常时。例如,您可能希望锁定文件的尝试可能会失败,因为其他人已将其锁定。在这种情况下,捕获异常并将其报告给用户是有意义的。在这种情况下,减少了什么被打破的不确定性;你不太可能通过清理使事情变得更糟。
其次,当您正在清理的资源是稀缺的系统资源时。例如,关闭finally块中的文件句柄是有意义的。 (“使用”当然只是编写try-finally块的另一种方式。)文件的内容可能已损坏,但现在你无能为力。文件句柄最终将被关闭,因此它可能会更快而不是更晚。