代码之家  ›  专栏  ›  技术社区  ›  Seth Spearman

尝试/最终(没有捕获)会冒泡异常吗?

  •  101
  • Seth Spearman  · 技术社区  · 14 年前

    我几乎肯定答案是肯定的。如果我使用Try Finally块,但不使用Catch块,则任何异常都将冒泡。对的?

    对这一做法有什么看法吗?

    赛斯

    2 回复  |  直到 14 年前
        1
  •  119
  •   Jon Skeet    14 年前

    是的,绝对会的。假设你 finally

        2
  •  57
  •   Eric Lippert    14 年前

    对这一做法有什么看法吗?

    对。 小心 . 当您的finally块运行时,它完全有可能正在运行,因为 引发了未处理的意外异常 . 也就是说 破碎的 ,和 完全出乎意料的事情 可能会发生。

    在这种情况下,可以说根本不应该在finally块中运行代码。finally块中的代码可能被构建为假设它所依赖的子系统是健康的,而实际上它们可能被严重破坏。finally块中的代码可能会使情况更糟。

    例如,我经常看到这样的事情:

    DisableAccessToTheResource();
    try
    {
        DoSomethingToTheResource();
    }
    finally
    {
        EnableAccessToTheResource();
    }
    

    这段代码的作者在想“我正在对世界的状态做一个暂时的改变;我需要把这个状态恢复到被称为我之前的状态”。但让我们想想所有可能出错的方法。

    首先,调用方可能已经禁用了对资源的访问;在这种情况下,此代码可能会过早地重新启用它。

    其次,如果DoSomethingToTheResource抛出异常,那么启用对资源的访问是正确的吗??? 管理资源的代码是 意外损坏 . 这个代码实际上是“如果管理代码被破坏, 确保其他代码可以尽快调用该损坏的代码,这样它也会可怕地失败 “这似乎是个坏主意。

    第三,如果doSomethingtothersource抛出异常,那么我们如何知道EnableAccessToTheResource也不会抛出异常?无论在使用资源之前发生什么异常,都可能会影响清理代码,在这种情况下,原始异常将丢失,问题将更难诊断。

    我倾向于这样编写代码,而不使用try finally块:

    bool wasDisabled = IsAccessDisabled();
    if (!wasDisabled)
        DisableAccessToTheResource();
    DoSomethingToTheResource();
    if (!wasDisabled)
        EnableAccessToTheResource();
    

    现在,除非有必要,否则国家不会发生变异。现在呼叫者的状态没有被搅乱。现在,如果dosomethingtothersource失败,那么我们不会重新启用访问。我们假设某个东西已经被严重破坏,并且不会因为试图继续运行代码而使情况变得更糟。如果可以的话,让打电话的人来处理这个问题。

    那么,什么时候做最后一个街区是个好主意呢?首先,当出现异常时。例如,您可能希望锁定文件的尝试可能会失败,因为其他人已将其锁定。在这种情况下,捕获异常并将其报告给用户是有意义的。在这种情况下,关于什么是坏的不确定性减少了;你不可能通过清理使事情变得更糟。

    其次,当您正在清理的资源是稀缺的系统资源时。例如,在finally块中关闭文件句柄是有意义的。(当然,“使用”只是编写try-finally块的另一种方式)文件的内容可能已损坏,但现在对此无能为力。文件句柄最终将被关闭,所以最好是早一点,而不是晚一点。