Поиск…


Вступление

Код, который компилирует, может по-прежнему сталкиваться с ошибками во время выполнения. В этом разделе перечислены наиболее распространенные из них, их причины и способы их устранения.

Ошибка времени выполнения «3»: возврат без GoSub

Неверный код

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

Почему это не работает?

Выполнение входит в процедуру DoSomething , переходит на метку DoThis , печатает «Привет!». на выход отладки, возвращается к инструкции сразу после вызова GoSub , печатает «Привет!». снова, а затем встречает оператор Return , но до сих пор некуда возвращаться , потому что мы не попали сюда с инструкцией GoSub .

Правильный код

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

Почему это работает?

Представляя инструкцию Exit Sub перед DoThis линии DoThis , мы DoThis подпрограмму DoThis от остальной части тела процедуры - единственный способ выполнить подпрограмму DoThis - через прыжок GoSub .

Другие примечания

GoSub / Return устарел, и его следует избегать в пользу фактических вызовов процедур. Процедура не должна содержать подпрограмм, кроме обработчиков ошибок.

Это очень похоже на ошибку времени выполнения «20»: возобновить без ошибок ; в обеих ситуациях решение состоит в том, чтобы гарантировать, что нормальный путь выполнения не может войти в подпрограмму (обозначенную меткой строки) без явного перехода (предполагая, что On Error GoTo считается явным скачком ).

Ошибка времени выполнения «6»: переполнение

неверный код

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

Почему это не работает?

Тип данных Integer - это 16-разрядное целое число со знаком с максимальным значением 32 767; присваивая его чему-либо большему, чем это приведет к переполнению типа и повышению этой ошибки.

Правильный код

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

Почему это работает?

Вместо этого вместо этого используется Long (32-разрядное) целое число, теперь мы можем создать цикл, который выполняет итерацию более 32 767 раз, не переполняя тип переменной счетчика.

Другие примечания

Дополнительные сведения см. В разделе Типы данных и лимиты .

Ошибка времени выполнения «9»: подстрочный индекс

неверный код

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

Почему это не работает?

foo - массив, содержащий 10 элементов. Когда счетчик циклов i достигает значения 11, foo(i) выходит за пределы диапазона . Эта ошибка возникает всякий раз, когда доступ к массиву или коллекции осуществляется с индексом, который не существует в этом массиве или коллекции.

Правильный код

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

Почему это работает?

Используйте функции LBound и UBound для определения нижней и верхней границ массива, соответственно.

Другие примечания

Когда индекс является строкой, например ThisWorkbook.Worksheets("I don't exist") , эта ошибка означает, что предоставленное имя не существует в запрошенной коллекции.

Фактическая ошибка является специфичной для реализации; Collection будет повышена ошибка во время выполнения 5 «Неверный вызов или аргумент процедуры»:

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

Ошибка времени выполнения «13»: несоответствие типов

неверный код

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

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

Почему это не работает?

VBA пытается очень тяжело преобразовать "42?" аргумент в значение Date . Когда он терпит неудачу, вызов DoSomethingElse не может быть выполнен, потому что VBA не знает, какую дату передать, поэтому он вызывает несоответствие типа ошибки 13 во время выполнения, поскольку тип аргумента не соответствует ожидаемому типу (и может 'также неявно преобразуется).

Правильный код

Public Sub DoSomething()
    DoSomethingElse Now
End Sub

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

Почему это работает?

Date аргумент Date процедуре, которая ожидает параметр Date , вызов может быть успешным.

Ошибка времени выполнения '91': переменная объекта или с не заданной переменной блока

неверный код

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

Почему это не работает?

Переменные объекта содержат ссылку , а ссылки должны быть заданы с помощью ключевого слова « Set . Эта ошибка возникает , когда вызов элемента выполнен на объекте, ссылка не является Nothing . В этом случае foo является ссылкой Collection , но он не инициализирован, поэтому ссылка содержит Nothing - и мы не можем вызвать .Add on Nothing .

Правильный код

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

Почему это работает?

.Add объектной переменной допустимую ссылку с помощью ключевого слова Set , вызовы .Add успешными.

Другие примечания

Часто функция или свойство может возвращать ссылку на объект - распространенным примером является метод Excel Range.Find , который возвращает объект Range :

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

Однако функция может очень хорошо вернуть Nothing (если поисковый .Row не найден), поэтому вполне вероятно, что .Row вызова .Row не выполняется.

Перед вызовом членов объекта убедитесь, что ссылка задана с условием 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

Ошибка времени выполнения «20»: возобновить без ошибок

неверный код

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

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

Почему это не работает?

Если процедура DoSomethingElse вызывает ошибку, выполнение переходит к CleanFail линии CleanFail , печатает номер ошибки, а команда Resume Next возвращается к инструкции, которая сразу же следует за строкой, в которой произошла ошибка, которая в этом случае является Debug.Print инструкция: подпрограмма обработки ошибок выполняется без контекста ошибки, и когда достигается команда Resume Next , возникает ошибка 20 времени выполнения, потому что возобновить ее некуда.

Правильный код

Sub DoSomething()
    On Error GoTo CleanFail
    DoSomethingElse

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

Почему это работает?

Представляя инструкцию Exit Sub перед CleanFail линии CleanFail , мы CleanFail подпрограмму обработки ошибок CleanFail от остальной части тела процедуры - единственный способ выполнить подпрограмму обработки ошибок - с помощью скачка On Error ; поэтому путь выполнения не доходит до инструкции Resume за пределами контекста ошибки, что позволяет избежать ошибки времени выполнения 20.

Другие примечания

Это очень похоже на ошибку времени выполнения «3»: возврат без GoSub ; в обеих ситуациях решение состоит в том, чтобы гарантировать, что нормальный путь выполнения не может войти в подпрограмму (обозначенную меткой строки) без явного перехода (предполагая, что On Error GoTo считается явным скачком ).



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow