恢复关键字

错误处理子例程将:

  • 运行到过程结束,在这种情况下,执行将在调用过程中重新开始。
  • 或者,使用 Resume 关键字在同一过程中恢复执行。

Resume 关键字只能在错误处理子例程中使用,因为如果 VBA 遇到 Resume 而没有处于错误状态,则会引发运行时错误 20无错误恢复

错误处理子例程可以通过多种方式使用 Resume 关键字:

  • Resume 单独使用,在导致错误的语句上继续执行。如果在执行此操作之前未实际处理错误,则将再次引发相同的错误,并且执行可能会进入无限循环。
  • Resume Next 导致错误的语句之后立即继续执行语句。如果在执行此操作之前未实际处理错误,则允许执行继续使用可能无效的数据,这可能导致逻辑错误和意外行为。
  • Resume [line label] 继续在指定的行标签 (或行号,如果你使用传统样式的行号)执行。这通常允许在干净地退出过程之前执行一些清理代码,例如确保在返回到调用者之前关闭数据库连接。

On Error Resume Next

On Error 语句本身可以使用 Resume 关键字指示 VBA 运行时有效地忽略所有错误

如果在执行此操作之前未实际处理错误,则允许执行继续使用可能无效的数据,这可能导致逻辑错误和意外行为

上面的重点不够强调。 On Error Resume Next 有效地忽略所有错误并将它们推到地毯下。一个程序在给定无效输入的情况下因运行时错误而爆炸是比使用未知/非预期数据运行的程序更好的程序 - 只是因为错误更容易识别。On Error Resume Next 可以轻松隐藏错误

On Error 语句是过程范围的 - 这就是为什么在给定的过程中通常只应该有一个这样的 On Error 语句。

但是,有时候错误条件不能完全避免,并且跳转到错误处理子程序只对 Resume Next 感觉不对。在这种特定情况下,已知可能失败的语句可以包含在两个 On Error 语句之间:

On Error Resume Next
[possibly-failing statement]
Err.Clear 'resets current error
On Error GoTo 0

On Error GoTo 0 指令在当前过程中重置错误处理,这样导致运行时错误的任何进一步指令将在该过程中未处理,而是传递调用堆栈,直到它被活动错误处理程序捕获。如果调用堆栈中没有活动的错误处理程序,则将其视为未处理的异常。

Public Sub Caller()
    On Error GoTo Handler
    
    Callee
    
    Exit Sub
Handler:
    Debug.Print "Error " & Err.Number & " in Caller."
End Sub

Public Sub Callee()
    On Error GoTo Handler
    
    Err.Raise 1     'This will be handled by the Callee handler.
    On Error GoTo 0 'After this statement, errors are passed up the stack.
    Err.Raise 2     'This will be handled by the Caller handler.    
    
    Exit Sub
Handler:
    Debug.Print "Error " & Err.Number & " in Callee."
    Resume Next
End Sub