Exit Sub
ErrorHandlerA:
...
Resume
End Sub
Resume 在这里,恢复正常执行(清除“错误处理模式”)并跳回到导致错误的指令。大概(希望?)... 包含使先前失败的调用成功的代码。
cleanUp:
con.close
rs.close
Exit Sub
ErrorHandlerB:
GoTo cleanup
End Sub
这里GoTo-跳出错误处理子程序,没有恢复到正常执行,所以cleanUp 行标签下的指令在错误处理上下文中执行。那应该是Resume cleanUp,而不是GoTo。
Exit Sub 语句离开作用域,清除错误状态并隐式恢复正常执行。这里有一点MCVE:
Public Sub Test()
On Error GoTo A
DoSomething
Debug.Print "After DoSomething: " & Err.Number
Exit Sub
A:
Debug.Print "Inside Test[A]: " & Err.Number
End Sub
Private Sub DoSomething()
On Error GoTo A
Err.Raise 5
B:
Debug.Print "Inside DoSomething[B]: " & Err.Number
Exit Sub
A:
Debug.Print "Inside DoSomething[A]: " & Err.Number
Resume B
End Sub
运行Test 过程会产生以下输出:
Inside DoSomething[A]: 5
Inside DoSomething[B]: 0
After DoSomething: 0
将Resume B 指令更改为GoTo B 会产生以下输出:
Inside DoSomething[A]: 5
Inside DoSomething[B]: 5
After DoSomething: 0
如您所见,由于在DoSomething 中处理了错误,因此当执行返回Test 时,错误状态被重置,并且永远不会触发Test 过程中的处理程序。
如果您想将错误传播给调用者,您有多种选择:
-
不要处理被调用过程中的错误。在上面的例子中,这意味着DoSomething 不会有On Error 语句;任何运行时错误都会“冒泡”调用堆栈,输出现在看起来像这样:
Inside Test[A]: 5
当调用代码知道最佳行动方案是什么时,您通常会这样做(例如,向用户显示MsgBox,或记录错误等)。
-
处理错误,然后重新提出错误。在您的示例中,这意味着将清理代码移动(或复制)到ErrorHandlerB 子例程中,并调用Err.Raise Err.Number 而不是Resume。或者您保留GoTo,然后清理子例程可以执行If Err.Number <> 0 Then Err.Raise Err.Number 以有效地重新抛出错误以供调用者处理。换句话说:
Public Sub Test()
On Error GoTo A
DoSomething
Debug.Print "After DoSomething: " & Err.Number
Exit Sub
A:
Debug.Print "Inside Test[A]: " & Err.Number
End Sub
Private Sub DoSomething()
On Error GoTo A
Err.Raise 5
B:
Debug.Print "Inside DoSomething[B]: " & Err.Number
If Err.Number <> 0 Then Err.Raise Err.Number
Exit Sub
A:
Debug.Print "Inside DoSomething[A]: " & Err.Number
GoTo B 'resuming would clear the error and prevent rethrow
End Sub
这个输出:
Inside DoSomething[A]: 5
Inside DoSomething[B]: 5
Inside Test[A]: 5
根据您希望在两个不同位置处理相同错误的确切原因,您还可以考虑将B 设为Function,它返回一个指示成功或失败的Boolean - 在这种情况下为@987654354 @ 本身不再处理错误,而是使用正常的流控制来确定要做什么:
Public Sub Test()
On Error GoTo A
If Not DoSomething Then
Debug.Print "After DoSomething failed: " & Err.Number
Exit Sub
End If
Exit Sub
A:
Debug.Print "Inside Test[A]: " & Err.Number
End Sub
Private Function DoSomething() As Boolean
'Dim success As Boolean
On Error GoTo A
Err.Raise 5
'success = True
B:
Debug.Print "Inside DoSomething[B]: " & Err.Number
DoSomething = (Err.Number = 0) 'DoSomething = success
Exit Function
A:
Debug.Print "Inside DoSomething[A]: " & Err.Number
'success = False
GoTo B 'Resume B
End Function
产生这个输出:
Inside DoSomething[A]: 5
Inside DoSomething[B]: 5
After DoSomething failed: 0
注意Test 知道DoSomething 失败,但Err.Number 为0。这通常比使用运行时错误进行流控制更可取,这再次取决于您的实际情况。另请注意,GoTo 跳转在这种情况下是可以避免的,使用一个简单的布尔局部变量来跟踪您的返回值(注释掉的代码)。