【发布时间】:2011-05-17 09:15:48
【问题描述】:
我几乎肯定答案是肯定的。如果我使用 Try finally 块但不使用 Catch 块,那么任何异常都会冒泡。对吗?
对一般实践有什么想法吗?
赛斯
【问题讨论】:
-
那么...什么是“泡沫”?它会扔还是躲?
标签: c# .net vb.net exception-handling
我几乎肯定答案是肯定的。如果我使用 Try finally 块但不使用 Catch 块,那么任何异常都会冒泡。对吗?
对一般实践有什么想法吗?
赛斯
【问题讨论】:
标签: c# .net vb.net exception-handling
是的,绝对会。当然,假设您的 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 块的另一种方式。)文件的内容可能已损坏,但现在您无能为力。文件句柄最终会被关闭,所以最好早点而不是晚点。
【讨论】: