VBA On错误语句

示例

即使使用了保护子句,也无法现实地始终考虑可能在过程主体中引发的所有可能的错误情况。该On Error GoTo语句指示VBA在运行时发生意外错误时跳转到行标签并进入“错误处理模式”。处理错误后,代码可以使用关键字恢复为“正常”执行Resume。

行标签表示子程序:因为子程序从传统的BASIC代码,并使用起源GoTo和GoSub跳跃和Return语句跳回“主”程序,它很容易编写难以跟随意大利面条代码,如果事情没有严格的结构。因此,最好:

  • 一个过程只有一个错误处理子例程

  • 错误处理子例程仅在错误状态下运行

这意味着处理其错误的过程应采用以下结构:

Private Sub DoSomething()
    On Error GoTo CleanFail

    'procedure code here

CleanExit:
    'cleanup code here
    Exit Sub

CleanFail:
    'error-handling code here
    Resume CleanExit
End Sub


错误处理策略

有时您想通过不同的操作来处理不同的错误。在这种情况下,您将检查全局Err对象,该对象将包含有关引发的错误的信息-并采取相应措施:

CleanExit:
    Exit Sub

CleanFail:
    Select Case Err.Number
        Case 9
            MsgBox "Specified number doesn't exist. Please try again.", vbExclamation
            Resume
        Case 91
            'woah there, this shouldn't be happening.
            Stop 'execution will break here
            Resume 'hit F8 to jump to the line that raised the error
        Case Else
            MsgBox "发生意外的错误:" & vbNewLine & Err.Description, vbCritical
            Resume CleanExit
    End Select
End Sub

作为一般准则,请考虑打开整个子例程或函数的错误处理,并处理其范围内可能发生的所有错误。如果只需要处理代码小部分中的错误,请在同一级别打开和关闭错误处理:

Private Sub DoSomething(CheckValue as Long)

    If CheckValue = 0 Then
        On Error GoTo ErrorHandler   ' turn error handling on
        ' code that may result in error
        On Error GoTo 0              ' turn error handling off - same level
    End If

CleanExit:
    Exit Sub

ErrorHandler:
    ' error handling code here
    ' do not turn off error handling here
    Resume

End Sub


行号

VBA支持旧式(例如QBASIC)行号。该Erl隐藏的属性可用于标识提出的最后一个错误的行号。如果您不使用行号,Erl则只会返回0。

Sub DoSomething()
10 On Error GoTo 50
20Debug.Print42 / 0
30 Exit Sub
40
50Debug.Print"在线错误 " & Erl ' returns 20
End Sub

如果你正在使用的行号,但不是一致,那么Erl将返回引发错误的指令之前的最后一个行号

Sub DoSomething()
10 On Error GoTo 50
  Debug.Print42 / 0
30 Exit Sub

50Debug.Print"在线错误 " & Erl 'returns 10
End Sub

请记住,这Erl也只有Integer精度,并且会默默地溢出。这意味着超出整数范围的行号将给出错误的结果:

Sub DoSomething()
99997 On Error GoTo 99999
99998Debug.Print42 / 0
99999
     Debug.PrintErl   'Prints 34462
End Sub

行号与导致错误的语句不太相关,并且对行进行编号很快变得乏味且不太易于维护。