即使使用了保护子句,也无法现实地始终考虑可能在过程主体中引发的所有可能的错误情况。该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
行号与导致错误的语句不太相关,并且对行进行编号很快变得乏味且不太易于维护。