VBA
Errori in fase di esecuzione VBA
Ricerca…
introduzione
Il codice che compila può ancora incorrere in errori, in fase di esecuzione. Questo argomento elenca i più comuni, le loro cause e come evitarli.
Errore di run-time '3': Ritorno senza GoSub
Codice non corretto
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Perché non funziona?
L'esecuzione entra nella procedura DoSomething
, DoThis
all'etichetta DoThis
, stampa "Ciao!" all'output di debug, ritorna all'istruzione immediatamente dopo la chiamata GoSub
, stampa "Ciao!" di nuovo, e poi incontra un'istruzione Return
, ma non c'è nessun luogo in cui tornare ora, perché non siamo arrivati qui con un'istruzione GoSub
.
Codice corretto
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Perché funziona?
Introducendo un'istruzione Exit Sub
prima DoThis
Line DoThis
, abbiamo separato la subroutine DoThis
dal resto del corpo della procedura - l'unico modo per eseguire la subroutine DoThis
è tramite GoSub
jump.
Altre note
GoSub
/ Return
è deprecato e dovrebbe essere evitato a favore delle chiamate di procedura effettive. Una procedura non dovrebbe contenere subroutine, tranne che gestori di errori.
Questo è molto simile all'errore di run-time '20': riprendi senza errori ; in entrambe le situazioni, la soluzione è garantire che il normale percorso di esecuzione non possa entrare in una sottorete (identificata da un'etichetta di linea) senza un salto esplicito (supponendo che On Error GoTo
sia considerato un salto esplicito ).
Errore di run-time '6': Overflow
codice non corretto
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
Perché non funziona?
Il tipo di dati Integer
è un intero con segno a 16 bit con un valore massimo di 32.767; assegnandolo a qualcosa più grande di quello traboccherà il tipo e aumenterà questo errore.
Codice corretto
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Perché funziona?
Usando invece un intero Long
(32-bit), possiamo ora creare un ciclo che itera più di 32.767 volte senza sovraccaricare il tipo della variabile del contatore.
Altre note
Vedi Tipi di dati e limiti per ulteriori informazioni.
Errore di run-time '9': indice fuori intervallo
codice non corretto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
Perché non funziona?
foo
è un array che contiene 10 elementi. Quando il contatore di loop i
raggiunge un valore di 11, foo(i)
è fuori portata . Questo errore si verifica ogni volta che si accede a una matrice o a una raccolta con un indice che non esiste in quell'array o raccolta.
Codice corretto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
Perché funziona?
Utilizzare le funzioni LBound
e UBound
per determinare rispettivamente i limiti inferiore e superiore di un array.
Altre note
Quando l'indice è una stringa, ad esempio ThisWorkbook.Worksheets("I don't exist")
, questo errore indica che il nome fornito non esiste nella raccolta interrogata.
L'errore effettivo è però specifico per l'implementazione; Collection
aumenterà l'errore di runtime 5 "Chiamata o argomento procedura non valida" invece:
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
Errore di run-time "13": tipo mancata corrispondenza
codice non corretto
Public Sub DoSomething()
DoSomethingElse "42?"
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Perché non funziona?
VBA sta provando davvero a convertire il "42?"
argomento in un valore Date
. Quando fallisce, la chiamata a DoSomethingElse
non può essere eseguita, perché VBA non sa quale data passare, quindi solleva la mancata corrispondenza di errore di tipo 13, perché il tipo dell'argomento non corrisponde al tipo previsto (e può essere implicitamente convertiti entrambi).
Codice corretto
Public Sub DoSomething()
DoSomethingElse Now
End Sub
Private Sub DoSomethingElse(foo As Date)
' Debug.Print MonthName(Month(foo))
End Sub
Perché funziona?
Passando un argomento Date
a una procedura che prevede un parametro Date
, la chiamata può avere successo.
Errore di run-time '91': variabile dell'oggetto o variabile di blocco With non impostata
codice non corretto
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Perché non funziona?
Le variabili oggetto contengono un riferimento e i riferimenti devono essere impostati utilizzando la parola chiave Set
. Questo errore si verifica ogni volta che viene effettuata una chiamata di membro su un oggetto il cui riferimento è Nothing
. In questo caso, foo
è un riferimento alla Collection
, ma non è inizializzato, quindi il riferimento contiene Nothing
- e non possiamo chiamare .Add
su Nothing
.
Codice corretto
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Perché funziona?
Assegnando alla variabile oggetto un riferimento valido utilizzando la parola chiave Set
, le chiamate .Add
esito positivo.
Altre note
Spesso, una funzione o una proprietà possono restituire un riferimento a un oggetto: un esempio comune è il metodo Range.Find
di Excel, che restituisce un oggetto Range
:
Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row
Tuttavia, la funzione può restituire Nothing
(se il termine di ricerca non viene trovato), quindi è probabile che la chiamata del membro .Row
concatenata non riesca.
Prima di chiamare i membri dell'oggetto, verificare che il riferimento sia impostato con una condizione 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
Errore di run-time '20': riprendi senza errori
codice non corretto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Perché non funziona?
Se la procedura DoSomethingElse
genera un errore, l'esecuzione salta CleanFail
linea CleanFail
, stampa il numero dell'errore e l'istruzione Resume Next
torna all'istruzione che segue immediatamente la riga in cui si è verificato l'errore, che in questo caso è Debug.Print
istruzione: la subroutine di gestione degli errori viene eseguita senza un contesto di errore e quando viene raggiunta l'istruzione Resume Next
, viene generato l'errore di run-time 20 perché non è possibile riprendere da nessuna parte.
Codice corretto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Perché funziona?
Introducendo un'istruzione Exit Sub
prima CleanFail
riga CleanFail
, abbiamo separato la subroutine di gestione degli errori di CleanFail
dal resto del corpo della procedura - l'unico modo per eseguire la subroutine di gestione degli errori è tramite un On Error
; pertanto, nessun percorso di esecuzione raggiunge l'istruzione Resume
al di fuori di un contesto di errore, che evita l'errore di runtime 20.
Altre note
Questo è molto simile all'errore di run-time '3': Return senza GoSub ; in entrambe le situazioni, la soluzione è garantire che il normale percorso di esecuzione non possa entrare in una sottorete (identificata da un'etichetta di linea) senza un salto esplicito (supponendo che On Error GoTo
sia considerato un salto esplicito ).