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. .AddNothing .

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 ).



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow