Excel VBA: В случае ошибки Перейти к инструкции, не работающей внутри For-Loop

Я пытаюсь пройти через таблицу в excel. Первые три столбца этой таблицы имеют текстовые заголовки, остальные имеют даты в виде заголовков. Я хочу назначить эти даты, последовательно переменной Date-type, а затем выполнить некоторые операции на основе даты

Для этого я использую цикл foreach на myTable.ListColumns. Поскольку первые три столбца не имеют заголовков дат, я попытался установить цикл таким образом, чтобы, если есть ошибка при назначении строки заголовка переменной типа даты, цикл переходит прямо к следующему столбцу

Это похоже на первый столбец. Однако, когда заголовок второго столбца "назначен" переменной типа даты, макрос обнаруживает ошибку, даже если он находится в блоке обработки ошибок

Dim myCol As ListColumn
For Each myCol In myTable.ListColumns
    On Error GoTo NextCol

    Dim myDate As Date
    myDate = CDate(myCol.Name)

    On Error GoTo 0

    'MORE CODE HERE

NextCol:
    On Error GoTo 0
Next myCol

Чтобы повторить, ошибка возникает во втором раунде цикла, в заявлении

myDate = CDate(myCol.Name)

Может ли кто-нибудь объяснить, почему оператор On Error перестает работать?

Ответ 1

С кодом, как показано, вы по-прежнему считаетесь находящимся в процедуре обработки ошибок, когда вы нажимаете оператор next.

Это означает, что последующие обработчики ошибок не разрешены до тех пор, пока вы не вернетесь с текущего.

Лучшей архитектурой будет:

    Dim myCol As ListColumn
    For Each myCol In myTable.ListColumns
        On Error GoTo ErrCol
        Dim myDate As Date
        myDate = CDate(myCol.Name)
        On Error GoTo 0
        ' MORE CODE HERE '
NextCol:
    Next myCol
    Exit Sub ' or something '

ErrCol:
    Resume NextCol

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

Этот сайт содержит хорошее описание проблемы:


Блокировка ошибок и ошибка при получении Перейти к

Блок обработки ошибок, также называемый обработчиком ошибок, представляет собой раздел кода, выполнение которого транслируется с помощью инструкции On Error Goto <label>:. Этот код должен быть разработан для устранения проблемы и возобновления выполнения в основном блоке кода или для прекращения выполнения процедуры. Вы не можете использовать оператор On Error Goto <label>:, просто пропустите строки. Например, следующий код не будет работать должным образом:

    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo Err2:
    Debug.Print 1 / 0
    ' more code
Err2:

Когда первая ошибка поднята, выполнение переходит к строке, следующей за Err1:. Обработчик ошибок по-прежнему активен при возникновении второй ошибки, и поэтому вторая ошибка не будет захвачена оператором On Error.

Ответ 2

Вам нужно добавить resume в свой код обработки ошибок, чтобы указать, что обработка ошибок завершена. В противном случае первый обработчик ошибок все еще активен, и вы никогда не будете "разрешены".

См. http://www.cpearson.com/excel/errorhandling.htm (в частности, заголовок "Обработка ошибок и ошибка при получении" и следующий раздел)

Ответ 3

Последующее наблюдение за принятым ответом paxdiablo. Это возможно, позволяя двум ловушкам ошибок в одном и том же субпоследовательности друг за другом:

Public Sub test()
    On Error GoTo Err1:
    Debug.Print 1 / 0
    ' more code
Err1:
    On Error GoTo -1     ' clears the active error handler
    On Error GoTo Err2:  ' .. so we can set up another
    Debug.Print 1 / 0
    ' more code
Err2:
    MsgBox "Got here safely"
End Sub

Использование On Error GoTo -1 отменяет активный обработчик ошибок и позволяет настроить другой (и err.clear не делает этого!). Является ли это хорошей идеей или нет, остается как упражнение для читателя, но оно работает!

Ответ 4

Удаление всех параметров свойств объекта Err не совпадает с сбросом обработчика ошибок.

Попробуйте следующее:

Sub TestErr()
Dim i As Integer
Dim x As Double
    On Error GoTo NextLoop
    For i = 1 To 2
10:     x = i / 0
NextLoop:
        If Err <> 0 Then
            Err.Clear
            Debug.Print "Cleared i=" & i
        End If
    Next
End Sub

Вы заметите точно так же, как OP, он правильно поймает ошибку, если i =1, но в строке 10 будет i = 2, но не будет работать, хотя мы использовали Err.Clear

Ответ 5

У меня была программа VBA, которая работала долгое время. Затем прерывание ошибок перестало работать. Посмотрел на все темы. Каким-то образом захват ошибок на моем компьютере был изменен, чтобы разбить все строки. Это можно найти на вкладке Developer/Visual Basic/Tools/Options/General (Ошибка Trapping). Должно быть установлено значение "Разрыв по необработанным ошибкам".