在錯誤語句上
即使有保護條款,也無法實際上總是考慮到程式正文中可能出現的所有可能的錯誤情況。On Error GoTo
語句指示 VBA 跳轉到*行標籤,*並在執行時發生意外錯誤時進入錯誤處理模式。處理完錯誤後,程式碼可以使用 Resume
關鍵字恢復 正常執行。
行標籤表示子程式 :因為子程式源自傳統的 BASIC 程式碼,並使用 GoTo
和 GoSub
jumps 和 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 "An unexpected error has occurred:" & 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
hidden 屬性可用於標識引發上一個錯誤的行號。如果你沒有使用行號,Erl
將只返回 0。
Sub DoSomething()
10 On Error GoTo 50
20 Debug.Print 42 / 0
30 Exit Sub
40
50 Debug.Print "Error raised on line " & Erl ' returns 20
End Sub
如果你正在使用的行號,但不能始終如一,那麼 Erl
將返回引發錯誤的指令之前的最後一個行號。
Sub DoSomething()
10 On Error GoTo 50
Debug.Print 42 / 0
30 Exit Sub
50 Debug.Print "Error raised on line " & Erl 'returns 10
End Sub
請記住,Erl
也只有 Integer
精度,並將無聲地溢位。這意味著整數範圍之外的行號將給出不正確的結果:
Sub DoSomething()
99997 On Error GoTo 99999
99998 Debug.Print 42 / 0
99999
Debug.Print Erl 'Prints 34462
End Sub
行號與導致錯誤的語句不太相關,編號行很快變得乏味且不太適合維護。