gpt4 book ai didi

VBA嵌套错误处理

转载 作者:行者123 更新时间:2023-12-01 21:57:39 25 4
gpt4 key购买 nike

我试图了解如何针对下面引用的情况设置错误处理。 Sub A 对其自己的上下文进行错误处理。然而,它调用 Sub B 创建数据库连接、结果集等,并在错误处理程序中进行清理。从目前的情况来看,似乎只有 ErrorHandler A 始终处于事件状态。如何在调用 B 时激活 ErrorHandler B 并在 B 返回后恢复到错误处理。

谢谢

Sub A
' Preps for database access
On Error GoTo ErrorHandlerA

B
.
.

Exit Sub
ErrorHandlerA:
...
Resume
End Sub

Sub B
' Does database access stuff

On Error ErrorHandlerB

cleanUp:
con.close
rs.close

Exit Sub
ErrorHandlerB:
GoTo cleanup

End Sub

最佳答案

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指示成功或失败 - 在这种情况下 A不再处理错误本身,而是使用正常的流程控制来确定要做什么:

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在这种情况下,跳转是可以避免的,使用一个简单的 bool 局部变量来跟踪您的返回值(注释掉的代码)。

关于VBA嵌套错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43124916/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com