在錯誤語句上

即使有保護條款,也無法實際上總是考慮到程式正文中可能出現的所有可能的錯誤情況。On Error GoTo 語句指示 VBA 跳轉到*行標籤,*並在執行時發生意外錯誤時進入錯誤處理模式。處理完錯誤後,程式碼可以使用 Resume 關鍵字恢復 正常執行。

行標籤表示子程式 :因為子程式源自傳統的 BASIC 程式碼,並使用 GoToGoSub 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

行號與導致錯誤的語句不太相關,編號行很快變得乏味且不太適合維護。