尝试/最后(没有Catch)冒泡异常吗?

时间:2010-11-29 16:27:46

标签: c# .net vb.net exception-handling

我几乎肯定答案是肯定的。如果我使用Try Finally块但不使用Catch块,那么任何异常都会冒泡。正确的吗?

对这种做法有何看法?

赛斯

2 个答案:

答案 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块的另一种方式。)文件的内容可能已损坏,但现在你无能为力。文件句柄最终将被关闭,因此它可能会更快而不是更晚。