logo
SrrazOffpril_Vecher

7.2. Иерархия обработчиков ошибок

Включенным (enabled) считается обработчик, установленный оператором On Error, а активным (active) – тот, чей код выполняется в данный момент времени. Чтобы активизировать обработчик, его нужно сначала включить, но не все включенные обработчики активны. Например, после выполнения оператора Resume обработчик деактивизируется, но остается включенным.

Когда ошибка происходит в процедуре, в которой нет своей подпрограммы обработки ошибок, или в активном обработчике ошибок, Visual Basic просматривает список вызовов в поисках другого включенного обработчика. Список вызовов – последовательность вызванных процедур, которая привела в данную точку потока управления; он отображается в диалоговом окне Call Stack (Стек вызова) меню View (Вид). Данное окно открывается только в режиме прерывания.

Если допустить такую последовательность вызовов:

  1. Процедура обработки события вызывает процедуру А.

  2. Процедура А вызывает процедуру В.

  3. Процедура В обращается к процедуре С.

То пока выполняется процедура С, другие процедуры приостанавливаются. Если в процедуре С возникает ошибка и в ней не окажется включенного обработчика ошибок, Visual Basic начинает просматривать процедуры в списке вызовов: сначала В, потом А и, наконец, дойдет до исходной процедуры обработки события (на ней этот процесс и закончится). При этом Visual Basic выполнит первый включенный обработчик ошибок из числа найденных. Не найдя ни одного включенного обработчика ошибок, он выведет на экран стандартное сообщение о неожиданной ошибке, после чего остановит программу. Если же Visual Basic найдет включенный обработчик ошибок, управление будет передано ему – так, будто ошибка произошла в процедуре, содержащей этот обработчик. Если в нем встретиться оператор Resume или Resume Next, выполнение возобновиться (таблица 7.2).

Таблица 7.2

Возобновление выполнения процедуры в соответствии с оператором, включенным в обработчик ошибок

Оператор

Результат

Resume

Повторяется вызов из только что найденной процедуры. В данном случае, если в процедуре А есть включенный обработчик ошибок и он выполнит оператор Resume, Visual Basic повторит вызов процедуры В

Resume Next

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

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

Если возникла ошибка, на которую данный обработчик не рассчитан, в содержащей его процедуре произойдет непредвиденная ошибка. В этом случае процедура может просто зациклиться, особенно если обработчик выполняет оператор Resume. Чтобы предотвратить подобную ситуацию, необходимо использовать в блоке Case Else обработчика метод Raise объекта Err. Это приведет к генерации ошибки в самом обработчике и заставит Visual Basic просматривать список вызовов в поисках обработчика, способного обработать эту ошибку.

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

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

- при отладке следует использовать во всех обработчиках ошибок метод Raise объекта Err, генерируя повторную ошибку для тех случаев, когда обработка не предусмотрена. Тогда программа пытается исправить ошибку в других обработчиках (из списка вызовов). А если это не удастся, Visual Basic гарантированно сообщит об ошибке, необрабатываемой кодом. Тестируя код и следуя этой методике, можно выявить ошибки, которые программа пока не в состоянии обрабатывать адекватно;

- если следует явным образом сбросить объект Err после обработки ошибки, необходимо применять метод Clear. Visual Basic автоматически вызывает данный метод после выполнения любой разновидности оператора Resume, а также операторов Exit Sub, Exit Function, Exit Property или одной из форм оператора On Error;

- если нет необходимости, чтобы ошибку перехватила другая процедура из списка вызовов, следует использовать оператор Stop, чтобы в таких случаях прерывать программу. На этапе разработки это позволит использовать контекст ошибки и улучшить код;

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