Лекция 4. Обработка ошибок

advertisement
Лекция 4. Обработка ошибок
Все ошибки, с которыми вы можете столкнуться, можно разделить на три категории:
Ошибки компиляции – следствие синтаксически неправильно написанного кода.
Если вы неверно введете ключевое слово, пропустите какой-то знак пунктуации или
укажете оператор Next без парного ему оператора For, Visual Basic обнаружит эти ошибки
при компиляции вашего кода.
Ошибки периода выполнения Возникают (и обнаруживаются Visual Basic) при
выполнении программы. Частая их причина – попытка выполнить недопустимую
операцию, например, деление на нуль.
Логические ошибки Программа работает не так, как задумал разработчик. Она может
быть написана синтаксически верно, работать корректно (т. е. не выполнять
недопустимых операций), но выдавать неправильные результаты.
Есть несколько способов избегать ошибок в программах:

тщательно прорабатывайте свои программы, выписывая на бумагу все возможные
события и определяя реакцию на каждое из них. Старайтесь четко формулировать
назначение каждой процедуры;

подробно комментируйте код и назначение каждой процедуры. Тогда, вернувшись
к программе спустя какое-то время, вам будет проще разобраться в ней;

по возможности явно ссылайтесь на объекты. Не используйте для этого типы
Variant и Object;

разработайте четкую схему именования переменных и объектов в своей программе;

очень часто проблемы возникают из-за ошибок в именах переменных или
использования одного элемента управления вместо другого. Чтобы избежать
ошибок в именах переменных, установите флажок Option Explicit (Явное
описание переменных).
Основные темы лекции:



структура программы, устойчивой к ошибкам;
варианты реализации обработчиков ошибок;
средства отладки а VB Editor.
Пример создания программы с обработчиком событий
Функция FileExists возвращает True, если указанный файл существует, и False, если
его нет, и при этом не содержит никакого кода обработки ошибок:
Function FileExists(filename) As Boolean
FileExists = ( Dir(filename) <> <> )
End Function
Функция Dir возвращает первый файл, соответствующий
заданной строке (она может
содержать знаки подстановки, имя диска и путь), или строку нулевой длины, если такого
файла не найдено. Однако, если функции передано имя несуществующего диска,
возникнет ошибка “устройство не доступно”. Если указанный диск является дисководом
(приводом для гибких дисков), функция будет работать правильно, только когда в
дисковод вставлена дискета. Если ее там нет, Visual Basic выдаст сообщение об ошибке
“диск не готов” и прекратит выполнение Вашей программы. Чтобы избежать фатального
исхода, вы должны перехватить ошибку и должным образом обработать ее.
Для работы с ошибками периода выполнения используется объект Err. Когда
возникает ошибка, Visual Basic устанавливает ряд свойств объекта Err: свойство Number
объекта Err содержит код ошибки, а свойство Description – ее краткое описание.
1
В общем случае процедура (или функция), содержащая средства обработки ошибок,
должна, кроме основных операторов, содержать и текст обработчика событий (error
handler). Такие обработчики целесообразно добавлять к любой процедуре, где существует
вероятность ошибки (строго говоря, следует исходить из того, что любой оператор Visual
Basic может стать источником ошибки, если только вам точно не известно обратное).
Структуру процедуры с обработчиком ошибок можно представить в следующем виде:
Sub MyProc()
On Error GoTo <метка> ‘ включение обработчика ошибок
< основная процедура>
Exit Sub ‘ выход из основной, если ошибок не обнаружено
< метка > : ‘ начало программы обработки ошибок
< распознавание ошибки и реакция на нее >
< выход из обработчика и возврат в тело основной процедуры >
End Sub
Обработчик ошибок автоматически отключается по завершении процедуры, в которой
он описан. Кроме того, можно отключать перехват ошибок, используя особый вариант
оператора On Error – On Error GoTo 0. Отключение перехвата ошибок удобно в
ситуации, когда вы хотите проигнорировать ошибку.
После метки обработчика ошибок вы должны предусмотреть распознавание кодов
возможных ошибок, анализируя (при помощи оператора Select…Case или If…Then…Else)
значение свойства Number объекта Err, и обеспечить обработку каждой из них. Напишите
также код для обработки непредвиденных ошибок, используя блок Else или Case Else.
Для выхода из программы обработки ошибок используется один из
операторов:

Resume [0] – Выполнение программы продолжается с инструкции, которая привела
к ошибке. В общем случае Resume используют, когда обработчик может исправить
ошибку для повторения операции после исправления ситуации, вызвавшей ошибку.

Resume Next – Если ошибка возникла в процедуре, в которой находится
обработчик, выполнение возобновляется с инструкции, следующей за той, что вызвала
ошибку. Если ошибка возникла вне процедуры, в которой находится обработчик,
выполнение возобновляется с инструкции, расположенной за вызовом внешней
процедуры, вызвавшей ошибку (но только при отсутствии в той своего обработчика
ошибок). Оператор Resume Next подходит и в том случае, когда ошибка возникает внутри
цикла и Вам нужно перезапустить операцию.

Resume метка – Выполнение программы продолжается с указанной метки в
процедуре, содержащей данный обработчик ошибок.
Например, аппаратные проблемы (недопустимое имя диска или пустой дисковод)
можно было бы обрабатывать так:
Function FileExists(filename) As Boolean
On Error GoTo CheckError
FileExists = (Dir(filename) <> “”)
Exit Function
CheckError: ‘ переходим сюда, если возникла ошибка
‘ определяем константы, соответствующие встроенным кодам ошибок Visual Basic
Const mnErrDiskNotReady = 71, mnErrDeviceUnavailable = 68
Select Case Err.Number
Case mnErrDiskNotReady
‘ открываем окно с восклицательным знаком, сообщением и кнопками ОК и Cancel
If MsgBox(“Диск не готов.”, vbExclamation & vbOKCancel) = vbOK Then
Resume
Else
Resume Next
End If
Case mnErrDeviceUnavailable
MsgBox “Устройство не доступно: “ & filename, vbExclamation
Resume Next
Case Else
2
‘ открываем окно со знаком “Stop”, сообщением и кнопкой ОК
MsgBox
“Неизвестная
ошибка
#”
&
Str(Err.Number)
Err.Description, vbCritical
Stop
End Select
Resume
End Function
“:”
&
Кратко прокомментируем работу этой функции. Когда Visual Basic генерирует ошибку
“Диск не готов”, программа выводит сообщение, позволяющее выбрать одну из двух
кнопок – OK или Cancel. Если пользователь выберет ОК, оператор Resume передаст
управление команде, вызвавшей ошибку, и попытается выполнить ее повторно. Если
пользователь исправил ситуацию, нормальное выполнение программы продолжится; в
ином случае управление вернется обработчику ошибок. Если же пользователь выберет
Cancel, оператор Resume Next передаст управление команде, следующей за той, что
вызвала ошибку (в нашем случае – оператору Exit Function).
При появлении ошибки ”Устройство не доступно”, программа выведет сообщение о
возникшей проблеме. После этого оператор Resume Next передаст управление команде,
следующей за той, что вызвала ошибку.
Если же произойдет некая непредвиденная ошибка, программа выведет краткое
описание ошибки, после чего прекратит свою работу оператором Stop.
Строчная обработка ошибок
Строчная обработка ошибок (inline error handling) заключается в том, что
программист сам проверяет специфическую строку кода, способную привести к ошибке.
В таком случае можно писать функции и операторы, возвращающие коды ошибок;
генерировать ошибки Visual Basic в вызванных процедурах и обрабатывать их в
вызывающих процедурах; создавать функции, которые возвращают тип данных Variant,
и использовать эти данные, чтобы сообщить об ошибке вызывающей процедуре.
Возврат кодов ошибок
Есть несколько способов вернуть код ошибки. Простейший – создать функции,
возвращающие в случае ошибки ее код этой ошибки. Вот пример использования этого
способа для функции FileExists, которая проверяет, существует ли указанный файл:
Function FileExists(p As String) As Long
If Dir(p) <> “” Then
FileExists = conSuccess ‘ эта константа сообщает, что такой
существует
Else
FileExists = conFailure ‘ эта константа сообщает об ошибке
End If
End Function
файл
Dim ResultValue As Long
ResultValue = FileExists(“C:\test.txt”)
If ResultValue = conFailure Then
. ‘ обрабатываем ошибку
Else
. ‘ продолжаем нормальное выполнение программы
End If
Главное в строчной обработке ошибок – немедленная проверка на ошибку после
выполнения каждого оператора или вызова функции. В этом случае можно создать
3
обработчик, рассчитанный на определенную группу ошибок. Такой подход не требует
реального появления ошибок периода выполнения.
Обработка ошибок в вызывающих процедурах
Другой способ состоит в генерации ошибки Visual Basic в вызываемой процедуре и ее
обработке строчным обработчиком ошибок в вызывающей процедуре. В следующем
примере функция FileExists при неудаче генерирует ошибку. Оператор On Error
Resume Next, добавленный перед вызовом этой функции, в случае ошибки заставляет
программу перейти к следующему за вызовом функции оператору, не выполняя
подпрограмму обработки ошибок.
Оператор On Error Resume Next сопровождается кодом обработки ошибок. Этот код
проверяет свойства объекта Err и определяет, была ли ошибка и каков ее номер. Если
Err.Number содержит ненулевое значение, значит, произошла ошибка, и программа
может предпринять соответствующие действия в зависимости от значений свойств
объекта Err.
Function FileExists(p As String)
If Dir(p) <> <> Then
Err.Raise conSuccess ‘ генерируем ошибку с кодом conSuccess
Else
Err.Raise conFailure ‘ генерируем ошибку с кодом conFailure
End If
End Function
Dim ResultValue As Long
On Error Resume Next
ResultValue = FileExists(«C:\Testfile.txt»)
If Err.Number = conFailure Then
. ‘ обрабатываем ошибку
Else
. ‘ продолжаем нормальное выполнение программы
End If
Использование типа данных Variant
Еще один способ вернуть информацию об ошибке построен на особенностях типа
данных Variant и связанных с ним функций. В Variant есть метка, которая указывает
тип содержащихся в переменной данных; одним из типов может быть код ошибки Visual
Basic. Поэтому Вы вправе написать функцию, возвращающую значение типа Variant, и
использовать его метку, сообщая вызывающей процедуре об ошибке.
Вот как переписать функцию Power, чтобы она возвращала значение типа Variant:
Function Power(X As Long, P As Integer) As Variant
On Error GoTo ErrorHandler
Power = x ^ P
Exit Function
ErrorHandler:
Power = CVErr(Err.Number) ‘ преобразуем код ошибки в значение Variant с
соответствующей меткой
End Function
‘ вызываем функцию Power
Dim varReturnValue As Variant
varReturnValue = Power(10, 2)
If lsError(varReturnValue) Then
. ‘ обрабатываем ошибку
Else
. ‘ продолжаем нормальное выполнение программы
4
End If
Общие принципы отладки
Отладочные средства Visual Basic поддерживают точки останова, контрольные
выражения (в том числе с остановом программы), пошаговое выполнение кода по одному
оператору или процедуре за шаг и просмотр значений переменных и свойств.
Visual Basic предоставляет и специфические возможности отладки, позволяя,
например, внести изменения в программу и продолжить ее выполнение, указать
следующий исполняемый оператор и протестировать процедуру в режиме прерывания.
Тестирование и отладка невозможны без понимания того, в каком из трех режимов
находится Ваша программа в каждый конкретный момент. Создавая программу, Вы
используете Visual Basic в режиме конструктора, а запуская ее, – в режиме выполнения. В
режиме прерывания программа приостанавливается, и Вы можете исследовать и изменять
значения переменных. Текущий режим подсказывает заголовок окна Visual Basic
(разработка, останов и выполнение).
Включенные обработчики ошибок часто мешают отладке программы. Конечно,
можно закомментировать строки On Error в каждом модуле проекта, но это слишком
утомительно. Вместо этого обработчики можно отключить на период отладки, с тем
чтобы при каждой ошибке отладчик переходил в режим прерывания. Для этого выберите
в редакторе Visual Basic из меню Tools (Сервис) команду Options (Параметры) и в
одноименном диалоговом окне на вкладке General (Общие) активизируйте переключатель
Break on All Errors (При любой ошибке). Теперь, как только где-нибудь в проекте
произойдет ошибка, Visual Basic перейдет в режим прерывания и покажет участок кода,
вызвавший ошибку.
Что дают средства отладки
Средства отладки предназначены специально для того, чтобы выявлять и устранять
любые проблемы в логике программы и ошибки периода выполнения, а также для того,
чтобы наблюдать за выполнением кода, не содержащего явных ошибок.
Например, неправильный результат может появиться в конце длинной цепочки
вычислений. При отладке главное – определить, где начались ошибки. Возможно, Вы
забыли инициализировать переменную, выбрали неподходящий оператор или указали
неверную формулу.
В отладке нет никаких фокусов, как нет и четких правил, действующих везде и
всегда. Отладка в основном помогает понять, что происходит при выполнении
программы. Средства отладки дают своего рода моментальный снимок текущего
состояния программы, включая значения переменных, выражений и свойств, а также
список активных вызовов процедур. И чем лучше Вы понимаете логику работы своей
программы, тем быстрее Вы отловите “жучков”.
В числе многих отладочных средств в Visual Basic есть набор очень полезных
инструментов, доступных через панель Debug (Отладка):
Run/Continue (Запуск/Продолжение)
Break (Прервать)
Reset (Сброс)
Toggle Breakpoint (Точка останова)
Step Into (Шаг с заходом)
Step Over (Шаг с обходом)
Call Stack (Стек вызова)
Quick Watch (Контрольное значение)
Watch Window (Окно контрольного значения)
5
Immediate Window (Окно отладки)
Locals Window (Окно локальных переменных)
Step Out (Шаг с выходом)

Run/Continue (Запуск/Продолжение) - Переключает из режима конструктора в
режим выполнения (Run) или из режима прерывания в режим выполнения (Continue). (В
режиме прерывания название кнопки меняется на Continue.)

Break (Прервать) - Останавливает выполнение программы и переключает в режим
прерывания.

Reset (Сброс) - Переключает из режима прерывания или выполнения в режим
конструктора.

Toggle Breakpoint (Точка останова) - Устанавливает или удаляет в текущей строке
точку останова (в этой точке Visual Basic приостанавливает выполнение программы).

Step Into (Шаг с заходом) - Выполняет следующую строку программы с заходом в
процедуры.

Step Over (Шаг с обходом) - Выполняет следующую строку программы без захода в
процедуры (полностью выполняя их).

Step Out (Шаг с выходом) - Выполняет оставшуюся часть текущей процедуры и
останавливает программу на следующей строке вызывающей процедуры.

Locals Window (Окно локальных переменных) - Открывает окно с текущими
значениями локальных переменных.

Immediate Window (Окно отладки) - Позволяет выполнить нужные операторы или
узнать значения переменных (программа должна быть в режиме прерывания).

Watch Window (Окно контрольного значения) - Открывает окно с текущими
значениями выбранных выражений.

Quick Watch (Контрольное значение) - Показывает текущее значение выражения
(программа должна быть в режиме прерывания).

Call Stack (Стек вызова) - Открывает диалоговое окно со списком вызванных, но
еще не завершенных процедур (программа должна быть в режиме прерывания).
Окна отладки
Иногда удается выявить источник проблем, выполнив часть кода. Но чаще
приходится анализировать и то, что происходит со значениями переменных и свойств. Вы
можете локализовать проблему, обнаружив неправильное значение у переменной или
свойства и определив, откуда оно взялось.
Контролировать значения выражений и переменных по мере выполнения операторов
программы позволяют отладочные окна. В Вашем распоряжении 3 таких окна: Immediate
(Проверка), Watch (Контрольные значения) и Locals (Локальные переменные). Чтобы
открыть любое из этих окон, выберите соответствующую команду из меню View (Вид)
или кнопку на панели инструментов Debug (Отладка).
Окно Immediate показывает информацию, полученную от отладочных операторов в
Вашем коде, или сообщает результат команды, набранной в этом окне.
Окно Watch показывает текущие контрольные выражения (watch expressions) , т. е.
выражения, чьи значения Вы решили контролировать при выполнении кода. Выражение,
вызывающее останов (break expression), . контрольное выражение, заставляющее Visual
Basic перейти в режим прерывания, как только заданное Вами условие становится
истинным. Колонка Context (Контекст) в окне Watch указывает процедуру, модуль или
модули, в которых оценивается контрольное выражение. Окно Watch может показать
результат вычисления контрольного выражения, если текущий оператор попадает в
указанный контекст, – иначе в колонке Value (Значение) появится сообщение о том, что
оператор находится вне контекста.
6
Окно Locals показывает значения всех переменных текущей процедуры.
Содержимое этого окна меняется по мере того, как поток управления переходит от
процедуры к процедуре. Переменная, представляющая объект, появляется в окне Locals
со знаком плюс (+) слева от ее имени. Вы можете щелкнуть знак плюс, чтобы .развернуть.
переменную, отобразив свойства объекта и их текущие значения. Если какое-то свойство
объекта содержит другой объект, его тоже можно .развернуть.. Сказанное относится и к
переменным, представляющим массивы или пользовательские типы.
Окно Immediate (Проверка)
Отлаживая программу или экспериментируя с ней, иногда нужно выполнять
отдельные процедуры, оценивать какие-то выражения или присваивать переменным и
свойствам новые значения. С этой целью можно использовать окно Immediate
(Проверка). Введя выражение в этом окне, Вы получите его значение.
Программный вывод информации
Метод Print пересылает вывод в окно Immediate всякий раз, когда Вы указываете
спецификатор объекта Debug. Например, следующий оператор выводит значение
переменной Salary в окно Immediate:
Debug.Print “Salary = “; Salary
Этот прием наиболее удобен, когда нужно наблюдать за значением переменной (в
данном случае – Salary) в том месте программы, где оно изменяется. Например,
показанный выше оператор можно было бы вставить внутрь цикла, изменяющего
значение Salary.
Присвоение значений переменным и свойствам
Пытаясь найти причину ошибки, Вы можете проверить, как влияют на программу те
или иные данные. Для этого (в режиме прерывания) Вы вводите нужные значения в окне
Immediate, например так:
VScrolll.Value = 100
MaxRows = 50
Первый оператор изменяет свойство объекта VScrolll, второй – присваивает новое
значение переменной MaxRows.
Установив требуемые значения свойств и переменных, Вы продолжаете выполнение
программы.
Проверка кодов ошибок
Окно Immediate (Проверка) позволяет просматривать сообщения, связанные с
конкретными кодами ошибок. Например, введя в окне Immediate оператор Error 58 и
нажав Enter, Вы увидите соответствующее сообщение об ошибке: “File already exists”
(“Файл уже существует”).
7
Несколько советов по отладке
Если Ваша программа дает некорректные результаты, просмотрите ее код и
попробуйте найти операторы, которые могли вызвать проблему. Поставьте на этих
операторах точки останова и перезапустите программу.

Приостановив программу, проверьте значения важнейших переменных и свойств.
Для этого используйте окна Quick Watch (Контрольное значение) и Immediate
(Проверка) или поставьте контрольные выражения.

Чтобы выявить место возникновения ошибки, активизируйте параметр Break on
All Errors (При любой ошибке); соответствующий переключатель Вы найдете на
вкладке General (Общие) диалогового окна Options (Параметры). Выполняйте программу
пошагово и, используя контрольные выражения и окно Locals (Локальные переменные),
следите, как изменяются значения переменных.

Если ошибка происходит в цикле, поставьте выражение, вызывающее прерывание,
– это позволит определить место возникновения проблемы. Затем используйте окно
Immediate (Проверка) и команду Set Next Statement (Задать следующую инструкцию),
чтобы перезапускать цикл после внесения исправлений.

8
Download