Обработка ошибок.
Независимо от того, насколько
тщательно разработана и отлажена программа, никогда нельзя полностью исключить
возможность возникновения ошибок. Поэтому при написании устойчивых программ
необходимо обрабатывать возникновение неисправимых ошибок. Команда, которая
применяется для их перехвата в конкретной процедуре, выглядит следующим
образом:
On Error GoTo...
где три точки означают метку (номер строки), определяющую
начало фрагмента обработки ошибки. Данный фрагмент должен размещаться в
рамках этой же процедуры. Невозможно при помощи команды On Error GoTo перейти
к другой процедуре. С другой стороны, фрагменты для перехвата ошибок часто
используются в других процедурах или функциях.
Метка для оператора перехвата
ошибки представляет собой любой идентификатор с последним символом в виде
двоеточия, удовлетворяющий соглашению об именованиях переменных. Метка
обозначает начало фрагмента программы, как показано ниже:
ErrorTrap:
'программный
код следует далее
Поскольку необходимо исключить
возможность "вылета" из программы в процедуре обработки ошибок, неплохой
идеей является использование оператора Exit в строке, непосредственно перед
меткой фрагмента по перехвату ошибок.
Команда On Error GoTo может
находиться в любом месте процедуры обработки события, функции или процедуры
Sub. Обычно там же размещается и программный код для обработки ошибок.
Единственным исключением является тот случаи, когда процедура вызывается
в рамках другой процедуры. Тогда Visual Basic сначала проверяет наличие
фрагмента по обработке ошибок сначала в текущей процедуре, а затем в "вышестоящей".
После того, как программист
начинает пользоваться обработкой ошибок при помощи On Error GoTo, в его
приложениях исчезают ошибки во время выполнения. (Но это не защищает от
ошибок в операционной системе; в Windows 95 их немного меньше, чем в Windows
3-х.) В любом случае команда On Error GoTo должна передавать управление
на участок кода, который идентифицирует проблему и, возможно, решает ее.
Если ошибку можно исправить, то оператор Resume
используется для возврата к месту в программе, где она случилась. Однако
невозможно исправить ошибку, не зная о вызвавшей ее причине. Это можно
сделать, используя функцию Err и объект Err. Он представляет собой целое
значение, которое можно присваивать переменной. Например, если написать
ErrorNumber = Err.Number
то значением переменной ErrorNumber будет номер
ошибки.
Visual Basic может идентифицировать
более 80 ошибок во время выполнения. (Информацию об этом необходимо искать
в электронной документации в разделе "trappable errors"). Ниже приведено
два примера.
Код ошибки
|
Объяснение
|
57
|
Ошибка ввода вывода (например,
попытка печати при выключеном принтере). |
68
|
Устройство недоступно (устройство
не существует или недоступно в данный момент). |
Способ использования данной
информации очень прост. Предположим, процедура обработки события использует
принтер. Где-нибудь внутри процедуры перед оператором печати необходимо
разместить строку
On Error GoTo PrinterCheck
Теперь перед оператором End Sub необходимо добавить
следующий код:
Exit sub
PrinterCheck:
ErrorNumber = Err. Number
Beep
Select Case ErrorNumber
Case
25
MsgBox "Your printer may be off-line."
Case
27
MsgBox "Is there a printer available?" Case Else
M$ = "Please tell the operator (= program author?) that"
M$ = M$ & vbCrLf '= Chr$(10) + Chr$(13) New Line
M$ = M$ & "error number " & ErrorNumber & " occurred."
MsgBox M$
End
End Select
М$
= "If the error has been corrected click on OK."
M$
= M$ & vbCrLf
M$
= M$ & "Otherwise click on Cancel."
Continue
= MsgBox(M$, vbOKCancel)
If
Continue = vbOK Then Resume Else End
Идея данного обработчика ошибок
очень проста, а оператор Select Case подходит в данном случае идеально.
В каждом отдельном случае программа проверяет тип ошибки и предлагает возможные
рекомендации по ее исправлению. Если достигнут оператор Case Else, то на
экране появляется номер ошибки. В любом случае после цикла по обработке
ошибок пользователю предлагается возможность выбора при помощи информационной
панели с двумя кнопками. Возможно, понадобится написать общую процедуру
для анализа ошибок. Тогда фрагмент по обработке ошибок в процедуре будет
передавать управление выше. После этого такую процедуру можно использовать
для перехвата и обработки ошибок во многих различных проектах.
Перехват ошибок не является панацеей. Например,
трудно что-либо сделать, если возникает сбой жесткого диска или в принтере
отсутствует бумага.
Вариант команды Resume позволяет
пропустить оператор, в котором возникла ошибка. Если использовать
Resume Next
Visual Basic начинает обрабатывать
оператор, находящийся непосредственно после текущего. Можно даже использовать
On Error Resume Next
для автоматического пропуска любого программного
кода, вызывающего ошибку. (Это приведено не случайно, хотя в данной главе
не применяется.)
Кроме того, можно возобновить
работу программы с любой строки кода, на которую указывает метка. Для этого
используется следующий оператор:
Resume Label
Обычно в Visual Basic метки
применяются только для обозначения фрагментов по обработке ошибок. Несмотря
на это, для совместимости с предыдущими версиями BASIC введен оператор
безусловного перехода GoTo, но нужда в нем возникает очень редко.
Команды Resume и Resume Next
ведут себя по-разному при возврате назад в том случае, когда ошибка произошла
в другой процедуре. Вспомним, что такое имеет место, когда одна процедура
вызывается из другой и в ней отсутствует фрагмент по обработке ошибок:
В обоих случаях Visual Basic не переходит к исходной процедуре. В случае
оператора Resume происходит повторный вызов процедуры. В случае Resume
Next Visual Basic начинает выполнять программу с первого (после вызова
процедуры) оператора. То есть не происходит возврата к исходной процедуре.
Предположим, что цепочка взаимосвязанных
процедур удлинилась: Процедура1 вызывает Процедуру2, а та, в свою очередь,
ФункциюЗ. Допустим, что ошибка происходит в момент выполнения ФункцииЗ,
но обработчик ошибок есть только у Процедуры1. Если в данном фрагменте
присутствует оператор Resume, то Visual Basic переходит к оператору, вызывающему
Процедуру2. Поскольку такой подход на самом деле очень громоздкий, то лучше
всегда полагаться только на обработчики ошибок, находящиеся в текущей процедуре.
Если одна процедура вызывает другую, то у нее необходимо отключить фрагмент
по обработке ошибок.
Существует еще одна функция для обработки ошибок,
Erl (Error Line). Если программист отчаялся найти строку, в которой возникает
ошибка, a Visual Basic не останавливается на данной строке, нужно проделать
следующее:
-
Добавить номера строк перед каждым оператором в процедуре.
-
Добавить оператор Debug.Print Eri в фрагмент по обработке
ошибок.
При разработке программ часто
необходимо протестировать функционирование обработчика ошибок. Visual Basic
включает в себя оператор
Error (номер кода ошибки)
который заставляет Visual Basic срабатывать так,
как будто произошла ошибка с указанным номером. Это облегчает процесс отладки
перехвата ошибок.
Если программист уверен в том, что программа
более не нуждается в обработчике ошибок, он может отключить его при помощи
оператора
On Error GoTo 0
(хотя значение 0 в общем-то не очень и необходимо).
Похожим образом можно изменить ссылку на другой обработчик ошибок, используя
другой оператор On Error GoTo. Необходимо убедиться, что между обработчиками
ошибок присутствует оператор Exit. Visual Basic использует последний оператор
On Error GoTo для того, чтобы решить, куда двигаться далее.
Подробнее
о объекте Err
Для того чтобы обеспечить более
централизованную обработку ошибок, когда это необходимо, Visual Basic использует
специальный объект Err, свойства которого можно анализировать после возникновения
ошибки. Ранее мы видели, как работает свойство Number (Err.Number), выдающее
номер ошибки.
Примечание: Microsoft рекомендует
использовать свойства и методы объекта Err вместо различного рода функций
обработки ошибок, за исключением только программ, написанных для более
ранних версий языка.
После того как выполняется
оператор Resume или On Error, все свойства объекта Err сбрасываются в 0
или сводятся к строке "". Свойства данного объекта инициализируются и после
выхода из функции или процедуры. Кроме того, для этого можно использовать
оператор
Err.Clear
Примечание: Правильным является
создание централизованного обработчика ошибок. Однако данной процедуре
необходимо передавать текущее значение различных свойств объекта Err. Если
вызвать объект Err из новой процедуры, все его значения будут инициализированы.
Если необходимо генерировать
ошибку для тестовых целей, можно использовать метод Raise объекта Err.
Его синтаксис следующий:
Err.Raise (Номер)
Совет: Можно использовать
метод Raise для определения собственных типов ошибок.
Если необходимо вывести описание текущей ошибки,
используется оператор
Err.Description
|