我几乎肯定答案是肯定的。如果我使用 Try finally 块但不使用 Catch 块,那么任何异常都会冒泡。正确的?
对一般实践有什么想法吗?
赛斯
是的,它绝对会。当然,假设您的 finally
块不会引发异常,在这种情况下,它将有效地“替换”最初引发的异常。
对一般实践有什么想法吗?
是的。当心。当你的 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 块的另一种方式。)文件的内容可能已损坏,但现在您无能为力。文件句柄最终将被关闭,所以它最好早点而不是晚点。
不定期副业成功案例分享