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). Должно быть установлено значение "Разрыв по необработанным ошибкам".