Szukaj…


Wprowadzenie

Kod, który się kompiluje, może nadal napotykać błędy w czasie wykonywania. W tym temacie wymieniono najczęstsze, ich przyczyny i sposoby ich unikania.

Błąd w czasie wykonywania „3”: Return bez GoSub

Błędny kod

Sub DoSomething()
    GoSub DoThis
DoThis:
    Debug.Print "Hi!"
    Return
End Sub

Dlaczego to nie działa?

Wykonanie wchodzi do procedury DoSomething , DoThis etykiety DoThis , drukuje „Cześć!” na wyjściu debugowania wraca do instrukcji natychmiast po wywołaniu GoSub , wypisuje „Cześć!” ponownie, a następnie napotyka instrukcję Return , ale nie ma do czego wrócić , ponieważ nie dotarliśmy tutaj z instrukcją GoSub .

Poprawny kod

Sub DoSomething()
    GoSub DoThis
    Exit Sub
DoThis:
    Debug.Print "Hi!"
    Return
End Sub

Dlaczego to działa?

Poprzez wprowadzenie Exit Sub dyspozycję przed DoThis linii etykiety, mamy posegregowane na DoThis podprogram od reszty ciała zabiegu - to jedyny sposób, aby wykonać DoThis podprogram jest przez GoSub skoku.

Inne notatki

GoSub / Return jest przestarzałe i należy go unikać na rzecz rzeczywistych wywołań procedur. Procedura nie powinna zawierać podprogramów innych niż procedury obsługi błędów.

Jest to bardzo podobne do błędu czasu wykonania „20”: Wznów bez błędu ; w obu sytuacjach rozwiązaniem jest upewnienie się, że normalna ścieżka wykonania nie może wejść do podprogramu (identyfikowanego przez etykietę linii) bez wyraźnego skoku (zakładając, że On Error GoTo jest uważany za skok jawny ).

Błąd w czasie wykonywania „6”: Przepełnienie

błędny kod

Sub DoSomething()
    Dim row As Integer
    For row = 1 To 100000
        'do stuff
    Next
End Sub

Dlaczego to nie działa?

Typ danych Integer to 16-bitowa liczba całkowita ze znakiem o maksymalnej wartości 32 767; przypisanie go do dowolnego większego elementu spowoduje przepełnienie typu i podniesienie tego błędu.

Poprawny kod

Sub DoSomething()
    Dim row As Long
    For row = 1 To 100000
        'do stuff
    Next
End Sub

Dlaczego to działa?

Używając Long (32-bitowej) liczby całkowitej, możemy teraz utworzyć pętlę, która iteruje ponad 32 767 razy bez przepełnienia typu zmiennej licznika.

Inne notatki

Aby uzyskać więcej informacji, zobacz Typy danych i limity .

Błąd czasu wykonania „9”: Indeks dolny poza zakresem

błędny kod

Sub DoSomething()
    Dim foo(1 To 10)
    Dim i As Long
    For i = 1 To 100
        foo(i) = i
    Next
End Sub

Dlaczego to nie działa?

foo to tablica zawierająca 10 elementów. Kiedy licznik pętli i osiągnie wartość 11, foo(i) jest poza zakresem . Ten błąd występuje, gdy dostęp do tablicy lub kolekcji jest uzyskiwany za pomocą indeksu, który nie istnieje w tej tablicy lub kolekcji.

Poprawny 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

Dlaczego to działa?

Użyj funkcji LBound i UBound aby określić odpowiednio dolną i górną granicę tablicy.

Inne notatki

Gdy indeks jest łańcuchem, np. ThisWorkbook.Worksheets("I don't exist") , ten błąd oznacza, że podana nazwa nie istnieje w kolekcji, której dotyczy zapytanie.

Rzeczywisty błąd zależy jednak od implementacji; Collection spowoduje zgłoszenie błędu czasu wykonania 5 „Niepoprawne wywołanie procedury lub argument”:

Sub RaisesRunTimeError5()
    Dim foo As New Collection
    foo.Add "foo", "foo"
    Debug.Print foo("bar")
End Sub

Błąd w czasie wykonywania „13”: Niezgodność typu

błędny kod

Public Sub DoSomething()
    DoSomethingElse "42?"
End Sub

Private Sub DoSomethingElse(foo As Date)
'    Debug.Print MonthName(Month(foo))
End Sub

Dlaczego to nie działa?

VBA próbuje naprawdę przekonwertować "42?" argument na wartość Date . Gdy się nie powiedzie, wywołanie DoSomethingElse nie może zostać wykonane, ponieważ VBA nie wie, która data ma zostać przekazana, dlatego podnosi niezgodność typu błędu 13 w czasie wykonywania, ponieważ typ argumentu nie pasuje do oczekiwanego typu (i może też nie może być pośrednio przekonwertowany).

Poprawny kod

Public Sub DoSomething()
    DoSomethingElse Now
End Sub

Private Sub DoSomethingElse(foo As Date)
'    Debug.Print MonthName(Month(foo))
End Sub

Dlaczego to działa?

Przekazując argument Date do procedury, która oczekuje parametru Date , wywołanie może się powieść.

Błąd czasu wykonania „91”: zmienna obiektowa lub zmienna blokowa nie została ustawiona

błędny kod

Sub DoSomething()
    Dim foo As Collection
    With foo
        .Add "ABC"
        .Add "XYZ"
    End With
End Sub

Dlaczego to nie działa?

Zmienne obiektowe zawierają odniesienie , a odniesienia należy ustawić za pomocą słowa kluczowego Set . Ten błąd występuje za każdym razem, gdy wywołanie elementu jest wykonywane na obiekcie, do którego odwołanie ma wartość Nothing . W tym przypadku foo jest odwołaniem do Collection , ale nie zostało zainicjowane, więc odwołanie Nothing zawiera Nothing - i nie możemy wywoływać .Add na Nothing .

Poprawny kod

Sub DoSomething()
    Dim foo As Collection
    Set foo = New Collection
    With foo
        .Add "ABC"
        .Add "XYZ"
    End With
End Sub

Dlaczego to działa?

Przypisując zmienną obiektową prawidłowe odwołanie za pomocą słowa kluczowego Set , wywołania .Add powodzeniem.

Inne notatki

Często funkcja lub właściwość może zwrócić odwołanie do obiektu - częstym przykładem jest metoda Excel Range.Find , która zwraca obiekt Range :

Dim resultRow As Long
resultRow = SomeSheet.Cells.Find("Something").Row

Jednak funkcja może bardzo dobrze zwracać Nothing (jeśli nie znaleziono .Row terminu), więc prawdopodobne jest, że połączenie łańcuchowe członka .Row nie powiedzie się.

Przed wywołaniem elementów obiektu sprawdź, czy odwołanie jest ustawione z warunkiem 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

Błąd w czasie wykonywania „20”: Wznów bez błędu

błędny kod

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

CleanFail:
    Debug.Print Err.Number
    Resume Next
End Sub

Dlaczego to nie działa?

Jeśli procedura DoSomethingElse CleanFail błąd, wykonanie przeskakuje do etykiety linii CleanFail , drukuje numer błędu, a instrukcja Resume Next przeskakuje z powrotem do instrukcji bezpośrednio po linii, w której wystąpił błąd, w tym przypadku jest to Debug.Print instrukcja: podprogram obsługi błędów jest wykonywany bez kontekstu błędów, a po osiągnięciu instrukcji Resume Next pojawia się błąd 20 w czasie wykonywania, ponieważ nie ma gdzie wznowić.

Poprawny kod

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

    Exit Sub    
CleanFail:
    Debug.Print Err.Number
    Resume Next
End Sub

Dlaczego to działa?

Wprowadzając instrukcję Exit Sub przed CleanFail linii CleanFail , oddzieliliśmy podprogram obsługi błędów CleanFail od reszty treści procedury - jedynym sposobem wykonania podprogramu obsługi On Error skok po On Error ; dlatego żadna ścieżka wykonania nie dociera do instrukcji Resume poza kontekstem błędu, co pozwala uniknąć błędu w czasie wykonywania 20.

Inne notatki

Jest to bardzo podobne do błędu w czasie wykonywania „3”: Return bez GoSub ; w obu sytuacjach rozwiązaniem jest upewnienie się, że normalna ścieżka wykonania nie może wejść do podprogramu (identyfikowanego przez etykietę linii) bez wyraźnego skoku (zakładając, że On Error GoTo jest uważany za skok jawny ).



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow