Suche…
Einführung
Code, der kompiliert wird, kann zur Laufzeit noch fehlerhaft sein. In diesem Thema werden die häufigsten Ursachen, ihre Ursachen und Möglichkeiten zur Vermeidung aufgeführt.
Laufzeitfehler '3': Rückgabe ohne GoSub
Falscher Code
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Warum funktioniert das nicht?
Die Ausführung tritt in die DoSomething
Prozedur ein, springt zum DoThis
Label und gibt "Hi!" Aus. kehrt der Befehl unmittelbar nach dem Aufruf von GoSub
zur Anweisung zurück und druckt "Hi!" wieder, und trifft dann auf eine Return
- Anweisung, aber es gibt nirgendwo jetzt zurück, weil wir hier nicht mit bekommen haben GoSub
- Anweisung.
Code korrigieren
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Warum funktioniert das?
Durch die Einführung eines Exit Sub
Anweisung vor der DoThis
Label Linie haben wir die getrennt DoThis
Unterprogramm von dem Rest des Verfahrens Körper - der einzige Weg , die auszuführen DoThis
Unterprogramm ist über den GoSub
Sprung.
Weitere Hinweise
GoSub
/ Return
ist veraltet und sollte zu Gunsten von Prozeduraufrufen vermieden werden. Eine Prozedur sollte keine anderen Unterprogramme als Fehlerbehandlungsroutinen enthalten.
Dies ist dem Laufzeitfehler '20' sehr ähnlich : Ohne Fehler fortfahren ; In beiden Situationen besteht die Lösung darin, sicherzustellen, dass der normale Ausführungspfad nicht ohne expliziten Sprung in eine Subroutine (durch ein Leitungsetikett gekennzeichnet) einsteigen kann (vorausgesetzt, On Error GoTo
wird als expliziter Sprung betrachtet ).
Laufzeitfehler '6': Überlauf
Falscher Code
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
Warum funktioniert das nicht?
Der Integer
Datentyp ist eine vorzeichenbehaftete 16-Bit-Ganzzahl mit einem Maximalwert von 32.767. Wenn Sie es einer größeren Größe zuweisen, wird der Typ überlaufen und dieser Fehler wird ausgelöst .
Korrigieren Sie den Code
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Warum funktioniert das?
Durch die Verwendung einer Long
-Ganzzahl (32-Bit) können wir jetzt eine Schleife erstellen, die mehr als 32.767-mal durchläuft, ohne den Typ der Zählervariable zu überlaufen.
Weitere Hinweise
Weitere Informationen finden Sie unter Datentypen und Grenzwerte .
Laufzeitfehler '9': Index außerhalb des gültigen Bereichs
Falscher Code
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
Warum funktioniert das nicht?
foo
ist ein Array, das 10 Elemente enthält. Wenn der i
Schleifenzähler einen Wert von 11 erreicht, ist foo(i)
außerhalb des Bereichs . Dieser Fehler tritt auf, wenn auf ein Array oder eine Sammlung mit einem Index zugegriffen wird, der in diesem Array oder dieser Sammlung nicht vorhanden ist.
Korrigieren Sie den Code
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
Warum funktioniert das?
Verwenden LBound
Funktionen LBound
und UBound
, um die Unter- bzw. Obergrenze eines Arrays zu bestimmen.
Weitere Hinweise
Wenn der Index eine Zeichenfolge ist, z. B. ThisWorkbook.Worksheets("I don't exist")
, bedeutet dieser Fehler, dass der angegebene Name in der abgefragten Sammlung nicht vorhanden ist.
Der tatsächliche Fehler ist jedoch implementierungsspezifisch. Collection
wird stattdessen der Laufzeitfehler 5 "Ungültiger Prozeduraufruf oder -argument" ausgelöst:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Laufzeitfehler '13': Typenkonflikt
Falscher Code
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Warum funktioniert das nicht?
VBA ist sehr bemüht, die "42?"
Argument in einen Date
. Wenn es fehlschlägt, wird der Anruf an DoSomethingElse
kann nicht ausgeführt werden, weil VBA nicht weiß , zu welchem Zeitpunkt zu passieren, so dass es wirft Laufzeitabgleichfehler 13 - Typ, da der Typ des Arguments nicht den erwarteten Typ übereinstimmt (und kann (kann nicht implizit konvertiert werden).
Korrigieren Sie den Code
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Warum funktioniert das?
Durch das Übergeben eines Date
Arguments an eine Prozedur, die einen Date
Parameter erwartet, kann der Aufruf erfolgreich sein.
Laufzeitfehler '91': Objektvariable oder Mit Blockvariable nicht gesetzt
Falscher Code
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Warum funktioniert das nicht?
Objektvariablen halten einen Verweis, und Referenzen müssen die gesetzt werden mit Set
- Schlüsselwort. Dieser Fehler tritt immer dann auf, wenn ein Member-Aufruf für ein Objekt ausgeführt wird, dessen Referenz Nothing
. In diesem Fall ist foo
eine Collection
, die jedoch nicht initialisiert ist. .Add
enthält die Referenz Nothing
- und wir können .Add
on Nothing
nicht aufrufen.
Korrigieren Sie den Code
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Warum funktioniert das?
Durch das Zuweisen der Objektvariablen mit dem Schlüsselwort Set
eine gültige Referenz, sind die Aufrufe von .Add
erfolgreich.
Weitere Hinweise
Häufig kann eine Funktion oder Eigenschaft eine Objektreferenz zurückgeben. Ein häufiges Beispiel ist die Range.Find
Methode von Excel, die ein Range
Objekt zurückgibt:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
Die Funktion kann jedoch sehr gut Nothing
(wenn der Suchbegriff nicht gefunden wird), so dass der verkettete .Row
Member-Aufruf wahrscheinlich fehlschlägt.
Stellen Sie vor dem Aufrufen von Objektmitgliedern sicher, dass der Verweis mit der Bedingung " If Not xxxx Is Nothing
ist:
Dim result As Range
Set result = SomeSheet.Cells.Find("Something")
Dim resultRow As Long
If Not result Is Nothing Then resultRow = result.Row
Laufzeitfehler '20': Ohne Fehler fortsetzen
Falscher Code
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Warum funktioniert das nicht?
Wenn die DoSomethingElse
Prozedur einen Fehler DoSomethingElse
, springt die Ausführung zur CleanFail
Zeilenbeschriftung, gibt die Fehlernummer aus und die Anweisung Resume Next
springt zurück zu der Anweisung, die unmittelbar auf die Zeile folgt, in der der Fehler aufgetreten ist, in diesem Fall Debug.Print
Anweisung: Die Fehlerbehandlungs-Subroutine wird ohne einen Fehlerkontext ausgeführt. Wenn die Anweisung Resume Next
erreicht wird, wird der Laufzeitfehler 20 ausgelöst, da nirgends weitergegangen werden kann.
Code korrigieren
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Warum funktioniert das?
Durch die Einführung einer Exit Sub
Anweisung vor der CleanFail
Zeilenbezeichnung haben wir die CleanFail
Fehlerbehandlungs-Subroutine vom Rest des Prozedurenkörpers getrennt. Die einzige Möglichkeit, die Fehlerbehandlungs-Subroutine auszuführen, ist über einen On Error
Sprung. Daher erreicht kein Ausführungspfad die Resume
Anweisung außerhalb eines Fehlerkontexts, wodurch der Laufzeitfehler 20 vermieden wird.
Weitere Hinweise
Dies ist dem Laufzeitfehler '3' sehr ähnlich : Return ohne GoSub ; In beiden Situationen besteht die Lösung darin, sicherzustellen, dass der normale Ausführungspfad nicht ohne expliziten Sprung in eine Subroutine (durch ein Leitungsetikett gekennzeichnet) einsteigen kann (vorausgesetzt, On Error GoTo
wird als expliziter Sprung betrachtet ).