Sök…
Introduktion
Kod som sammanställer kan fortfarande stöta på fel vid körning. I det här ämnet listas de vanligaste, orsakerna och hur man undviker dem.
Run-time error '3': Återvänd utan GoSub
Inkorrekt kod
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Varför fungerar det inte?
Exekvering går in i DoSomething
proceduren, hoppar till DoThis
etiketten, skriver ut "Hej!" till felsökningsutgången, återgår till instruktionen omedelbart efter GoSub
samtalet och skriver ut "Hej!" igen och möter sedan ett Return
uttalande, men det finns ingenstans att återvända till nu, för vi kom inte hit med ett GoSub
uttalande.
Rätt kod
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Varför fungerar det här?
Genom att introducera en Exit Sub
instruktion före DoThis
har vi separerat DoThis
från resten av procedurorganet - det enda sättet att utföra DoThis
är via GoSub
hoppet.
Andra anteckningar
GoSub
/ Return
avskrivs och bör undvikas till förmån för faktiska procedursamtal. Ett förfarande bör inte innehålla subroutiner, utom felhanterare.
Detta är mycket likt körfel '20': Fortsätt utan fel ; i båda situationerna är lösningen att säkerställa att den normala exekveringsvägen inte kan komma in i en underrutin (identifierad med en linjemärkning) utan ett uttryckligt hopp (förutsatt att On Error GoTo
anses vara ett uttryckligt hopp ).
Run-time error '6': Överflöde
Inkorrekt kod
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
Varför fungerar det inte?
Integer
är ett 16-bitars signerat heltal med ett maximivärde av 32 767; tilldela den till något större än det kommer att översvämma typen och höja detta fel.
Rätt kod
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Varför fungerar det här?
Genom att använda ett Long
(32-bitars) heltal istället kan vi nu skapa en slinga som itererar mer än 32,767 gånger utan att överfylla räknarvariabelns typ.
Andra anteckningar
Se Datatyper och gränser för mer information.
Run-time error '9': Prenumeration utanför räckvidden
Inkorrekt kod
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
Varför fungerar det inte?
foo
är en matris som innehåller 10 artiklar. När i
loop-räknaren når ett värde av 11, är foo(i)
utanför räckvidden . Det här felet uppstår när en matris eller samling har åtkomst med ett index som inte finns i den arrayen eller samlingen.
Rätt kod
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
Varför fungerar det här?
Använd LBound
och UBound
funktioner för att bestämma de nedre respektive övre gränserna för en matris.
Andra anteckningar
När indexet är en sträng, t.ex. ThisWorkbook.Worksheets("I don't exist")
, betyder detta fel att det medföljande namnet inte finns i den frågade samlingen.
Det faktiska felet är dock implementeringsspecifikt; Collection
kommer att höja körtidfel 5 "Ogiltigt procedursamtal eller argument" istället:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Driftstidsfel '13': Skriv felinställning
Inkorrekt kod
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Varför fungerar det inte?
VBA försöker verkligen hårt för att konvertera "42?"
argument till ett Date
. När det misslyckas kan inte samtalet till DoSomethingElse
, eftersom VBA inte vet vilket datum som ska passera, så det väcker körtid-fel 13- typmatchning , eftersom argumentets typ inte stämmer med den förväntade typen (och kan kan inte antydas konverteras antingen).
Rätt kod
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Varför fungerar det här?
Genom att skicka ett Date
argument till en procedur som förväntar sig en Date
parameter, kan samtalet lyckas.
Körningsfel '91': Objektvariabel eller Med blockvariabel inte inställd
Inkorrekt kod
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Varför fungerar det inte?
Objektvariabler har en referens , och referenser måste ställas in med hjälp av Set
nyckelordet. Det här felet uppstår varje gång ett medlemssamtal görs på ett objekt vars referens är Nothing
. I det här fallet är foo
en Collection
, men den är inte initialiserad, så referensen innehåller Nothing
- och vi kan inte ringa. .Add
på Nothing
.
Rätt kod
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Varför fungerar det här?
Genom att tilldela objektvariabeln en giltig referens med hjälp av Set
nyckelordet lyckas .Add
samtal.
Andra anteckningar
Ofta kan en funktion eller egenskap returnera en objektreferens - ett vanligt exempel är Excel's metod Range.Find
, som returnerar ett Range
objekt:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
Men funktionen kan mycket väl returnera Nothing
(om sökordet inte hittas), så det är troligt att det kedjade .Row
medlemmens samtal misslyckas.
Innan du ringer objektmedlemmar, kontrollera att referensen är inställd på ett villkor 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
Run-time error '20': Fortsätt utan fel
Inkorrekt kod
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Varför fungerar det inte?
Om DoSomethingElse
proceduren väcker ett fel, hoppar CleanFail
linjen etikett CleanFail
, skriver ut felnumret och instruktionen Resume Next
hoppar tillbaka till instruktionen som omedelbart följer raden där felet inträffade, vilket i detta fall är Debug.Print
instruktion: felhanteringssubutinen exekveras utan felkontext, och när instruktionen Resume Next
uppnås höjs körtid 20 eftersom det inte finns någonstans att återuppta.
Rätt kod
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Varför fungerar det här?
Genom att införa en Exit Sub
instruktion före CleanFail
har vi separerat CleanFail
-felhanteringssubutinen från resten av procedurorganet - det enda sättet att utföra subhutroen för felhantering är via ett On Error
hopp; därför når ingen exekveringsväg Resume
instruktionen utanför ett felkontext, vilket undviker körtid 20.
Andra anteckningar
Detta är mycket liknande körtid-fel '3': Återvänd utan GoSub ; i båda situationerna är lösningen att säkerställa att den normala exekveringsvägen inte kan komma in i en underrutin (identifierad med en linjemärkning) utan ett uttryckligt hopp (förutsatt att On Error GoTo
anses vara ett uttryckligt hopp ).