Zoeken…
Invoering
Code die wordt samengesteld, kan tijdens runtime nog steeds fouten bevatten. Dit onderwerp geeft een overzicht van de meest voorkomende oorzaken, hun oorzaken en hoe u ze kunt vermijden.
Runtime error '3': Return zonder GoSub
Foute code
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Waarom werkt dit niet?
Uitvoering voert de DoSomething
procedure in, springt naar het DoThis
label en drukt "Hallo!" naar de foutopsporingsuitvoer, keert onmiddellijk na de GoSub
oproep terug naar de instructie en drukt "Hallo!" en ontmoet vervolgens een Return
instructie, maar er is nergens om naar terug te keren , omdat we hier niet zijn gekomen met een GoSub
instructie.
Juiste code
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Waarom werkt dit
Door een Exit Sub
instructie voor het DoThis
introduceren, hebben we de DoThis
subroutine gescheiden van de rest van de procedure - de enige manier om de DoThis
subroutine uit te voeren is via de GoSub
sprong.
Andere notities
GoSub
/ Return
is verouderd en moet worden vermeden ten gunste van daadwerkelijke procedureaanroepen. Een procedure mag geen subroutines bevatten, behalve foutafhandelaars.
Dit lijkt erg op Runtime-fout '20': zonder fout hervatten ; in beide situaties is de oplossing ervoor te zorgen dat het normale uitvoeringspad geen subroutine (geïdentificeerd door een lijnlabel) kan betreden zonder een expliciete sprong (ervan uitgaande dat On Error GoTo
als een expliciete sprong wordt beschouwd).
Runtime error '6': Overflow
foute code
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
Waarom werkt dit niet?
Het gegevenstype Integer
is een 16-bits geheel getal met teken met een maximale waarde van 32.767; toe te wijzen aan iets groter dan die van het type overstromen, en deze fout te verhogen.
Juiste code
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Waarom werkt dit
Door in plaats daarvan een Long
(32-bits) geheel getal te gebruiken, kunnen we nu een lus maken die meer dan 32.767 keer itereert zonder het type van de tellervariabele te overlopen.
Andere notities
Zie Gegevenstypen en -limieten voor meer informatie.
Runtime-fout '9': subscript buiten bereik
foute code
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
Waarom werkt dit niet?
foo
is een array met 10 items. Wanneer de i
lusteller een waarde van 11 bereikt, is foo(i)
buiten bereik . Deze fout treedt op wanneer een matrix of verzameling wordt geopend met een index die niet bestaat in die matrix of verzameling.
Juiste 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
Waarom werkt dit
Gebruik de functies LBound
en UBound
om respectievelijk de onderste en bovenste grenzen van een array te bepalen.
Andere notities
Wanneer de index een tekenreeks is, bijvoorbeeld ThisWorkbook.Worksheets("I don't exist")
, betekent deze fout dat de opgegeven naam niet voorkomt in de opgevraagde collectie.
De werkelijke fout is echter implementatiespecifiek; Collection
zal runtime-fout 5 "Ongeldige procedureaanroep of argument" veroorzaken:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Runtime error '13': Type mismatch
foute code
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Waarom werkt dit niet?
VBA probeert heel hard om de "42?"
argument in een Date
waarde. Als het mislukt, kan de aanroep van DoSomethingElse
niet worden uitgevoerd, omdat VBA niet weet welke datum moet worden doorgegeven, dus het leidt tot run-time error 13 type mismatch , omdat het type argument niet overeenkomt met het verwachte type (en kan worden ook niet impliciet geconverteerd).
Juiste code
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Waarom werkt dit
Door een Date
argument door te geven aan een procedure die een Date
parameter verwacht, kan de aanroep slagen.
Runtime-fout '91': objectvariabele of met blokvariabele niet ingesteld
foute code
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Waarom werkt dit niet?
Objectvariabelen bevatten een referentie en referenties moeten worden ingesteld met het trefwoord Set
. Deze fout treedt op wanneer een lid wordt gebeld op een object waarvan de referentie Nothing
. In dit geval is foo
een Collection
, maar het is niet geïnitialiseerd, dus de referentie bevat Nothing
- en we kunnen niet bellen. .Add
Nothing
.
Juiste code
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Waarom werkt dit
Door de objectvariabele een geldige referentie toe te wijzen met behulp van het trefwoord Set
, slagen de .Add
aanroepen.
Andere notities
Vaak kan een functie of eigenschap een objectverwijzing retourneren - een veelvoorkomend voorbeeld is de methode Range.Find
Excel, die een Range
object retourneert:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
De functie kan echter heel goed Nothing
retourneren (als de zoekterm niet wordt gevonden), dus het is waarschijnlijk dat de geketende .Row
lid-oproep mislukt.
Voordat u objectleden oproept, controleert u of de referentie is ingesteld met de voorwaarde If Not xxxx Is Nothing
:
Dim result As Range
Set result = SomeSheet.Cells.Find("Something")
Dim resultRow As Long
If Not result Is Nothing Then resultRow = result.Row
Runtime-fout '20': zonder fout hervatten
foute code
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Waarom werkt dit niet?
Als de procedure DoSomethingElse
een fout oproept, springt de uitvoering naar het CleanFail
, drukt het foutnummer af en springt de instructie Resume Next
terug naar de instructie die onmiddellijk volgt op de regel waar de fout is opgetreden, in dit geval Debug.Print
instructie: de foutafhandelingssubroutine wordt uitgevoerd zonder een foutcontext, en wanneer de instructie Resume Next
wordt bereikt, wordt runtime-fout 20 opgeworpen omdat er nergens naartoe kan worden hervat.
Juiste code
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Waarom werkt dit
Door een Exit Sub
instructie voor het CleanFail
introduceren, hebben we de CleanFail
-foutafhandelings-subroutine gescheiden van de rest van de procedure - de enige manier om de foutafhandelings-subroutine uit te voeren is via een On Error
sprong; daarom bereikt geen uitvoeringspad de instructie Resume
buiten een foutcontext, waardoor runtime-fout 20 wordt vermeden.
Andere notities
Dit lijkt erg op Run-time error '3': Return without GoSub ; in beide situaties is de oplossing ervoor te zorgen dat het normale uitvoeringspad geen subroutine (geïdentificeerd door een lijnlabel) kan betreden zonder een expliciete sprong (ervan uitgaande dat On Error GoTo
als een expliciete sprong wordt beschouwd).