异常处理:在抛出异常后,finally块是否会被执行?

18
假设您有以下代码:
而不是执行以下操作:
Try
    '
    ' Initialize some objects
    '

    '
    ' do something that fails
    '

    '
    ' Clean up-code that gets not reached because exception
    '
Catch e As Exception
    '
    'Clean up initialized objects
    '

    Throw e
End Try

我想要做以下操作:

Try
    '
    ' Initialize some objects
    '

    '
    ' do something that fails
    '
Catch e As Exception
    Throw e
Finally
    '
    'Clean up initialized objects
    '
End Try

我的简单问题是:在发生异常的情况下,即使在几行代码之前有一个抛出语句,finally块是否会被执行?

[编辑] 感谢您的快速回答。

我认为第一行会出现NullReference、COM和FileNotFound异常。

好的,我将使用这段代码:

Try
    '
    ' Initialize some objects
    '

    '
    ' do something that fails
    '
Catch e As Exception      ' or just "Catch"??        
    Throw
Finally
    '
    'Clean up initialized objects
    '
End Try

祝您一切顺利!

Inno


2
你不应该写 Throw e 而是只写 Throw。否则,你会重置异常堆栈跟踪,从而丢失有关最初引发异常的信息。 - Thomas Levesque
5个回答

25
所以我的简单问题是:如果在某些行抛出异常,那么 finally 块是否会被执行?
是的。Finally 块始终1)被执行,正是为了清理工作。在您的代码中,删除 Catch 块,它什么也不做。更糟糕的是,它实际上会破坏堆栈跟踪,因为您没有重新抛出原始异常,而是抛出了新异常。
如果您真的需要一个 Catch 块,然后重新抛出异常,请使用以下内容:
Catch e As XyzException
    ' … do some stuff. '
    Throw
End Try

1): 购买者自负责任:有一些异常情况,如StackOverflowException(多么合适的名称...)需要特别注意,并且可能不会触发Finally块。正确处理它们通常相当困难。


1
Konrad - 最终语句并不总是被执行。例如,当出现OutOfMemoryException时,它将不会被执行。 - Pete OHanlon
1
@Pete:你是不是指的StackOverflowException?很容易制作一个测试,在OutOfMemoryException的情况下运行finally。 - Brian Rasmussen
1
@Konrad:我不能确定 OOME 是否会阻止 finally 块运行,但我之前没有听说过这种情况。然而,很容易构造出一种情况使其运行,因此 Pete 的观点并不完全正确。另一方面,SOE 会使运行时崩溃,据我所知,这将始终阻止 finally 块的运行。 - Brian Rasmussen
1
@Luke:感谢您的更新和链接。我不知道OOME可以做到这一点。然而,这并不等同于“当您遇到OOME时它将不会被执行”,这正是我试图澄清的事情。 - Brian Rasmussen
@Konrad:我会说,“在 'finally' 子句后面的代码不会在 'finally' 子句之前执行。线程可能会陷入无限循环或死亡并停止完全执行代码,但是 finally 块中的代码永远不会被“跳过”。”。 - supercat
显示剩余3条评论

5

不,它并不能保证运行。有一些例外情况 - 比如 StackOverflowException 和 OutOfMemoryException - 在这些情况下,finally 块的执行是不能保证的。


1
在几乎所有情况下,Finally 语句块都会在 Try/Catch 块中执行(特别的例外是当 StackOverflowException 或 OutOfMemoryException 发生时)。但我很好奇,为什么你不亲自尝试一下呢?实际尝试是学习知识的宝贵方式之一,毕竟你可能会接受一个错误或误导性的答案,从此以后就会被这个错误观点所束缚。

1
我尝试了这个,但我的调试器在抛出异常处停止了。我阅读了文档,但没有找到关于我的问题的提示。我提出了这些问题,以获得直接与我的问题相关和间接相关的答案(例如“finally”在特殊情况下不会被执行的提示)。 - Inno

1

注意:System.Environment.FastFail方法会立即终止当前进程/线程,而不执行finally部分。


0

是的,无论如何 finally 块都会被执行。(当然也有一些例外情况,比如 Response.Redirect 和某些多线程情况)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接