Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Л 9.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
136.19 Кб
Скачать

Обработка исключительных ситуаций

Виды ошибок. Классы исключений. Обработка исключений. Преднамеренная генерация исключений. Особенности отладки обработчиков исключений.

Исключительная ситуация как класс

Исключительная ситуация — это некое нештатное событие, могущее повлиять на дальнейшее выполнение программы.

Чем же различаются между собой исключительные ситуации? Как отличить одну исключительную ситуацию от другой? Поскольку это объекты, они отличаются классом (объектным типом). В модуле SYSUTILS.PAS описан объектный тип Exception. Он является предком для всех других объектов — исключительных ситуаций. Вот он:

Exception = class(TObject)

 private

FMessage: string;

ExceptClass = class of Exception;

Как видно из приведенного описания класса Exception, у него имеется двенадцать (!) конструкторов, позволяющих задействовать при создании объекта текстовые строки из ресурсов приложения (имя включает строку Res), форматирование текста (включает Fmt), связь с контекстом справочной системы (включает Help).

Конструкторы, в названии которых встречается подстрока Fmt, могут вставлять в формируемый текст сообщения об ошибке значения параметров, как это делает стандартная функция Format:

If MemSize > Limit then

raise EOutOfMemory.CreateFmt('Cannot allocate more than %d 

bytes',[Limit]);

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

Если в названии фигурирует подстрока Help, то такой конструктор инициализирует свойство HelpContext создаваемого объекта. Естественно, система помощи должна быть создана и в ней должна иметься статья, связанная с этим контекстом. Теперь пользователь может затребовать помощь для данной ситуации, скажем, нажав клавишу <F1> в момент показа сообщения об ИС.

Тип Exception порождает многочисленные дочерние типы, соответствующие часто встречающимся случаям ошибок ввода/вывода, распределения памяти и т. п. Дерево исключительных ситуаций Delphi 7 приведено на рис. 3.1.

Заметим, что тип Exception и его потомки представляют собой исключение из правила, предписывающего все объектные типы именовать с буквы Т.

Потомки Exception начинаются с Е, например EZeroDivide.

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

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

Рис. 3.1. Дерево объектов исключительных ситуаций Delphi 7

Таблица 3.1. Исключительные ситуации при работе с памятью (порождены от EHeapException)

Тип

Условие возникновения

EOutOfMemory

Недостаточно места в куче (памяти)

EOutOfResources

Нехватка системных ресурсов

EInvalidPointer

Недопустимый указатель (обычно nil)

Таблица 3.2. Исключительные ситуации целочисленной математики (порождены от EIntError)

Тип

Условие возникновения

EDivByZero

Попытка деления на ноль (целое число)

ERangeError

Число или выражение выходит за допустимый диапазон

EIntOverflow

Целочисленное переполнение

Таблица 3.3. Исключительные ситуации математики с плавающей точкой (порождены от EMathError)

Тип

Условие возникновения

EInvalidOp

Неверная операция

EZeroDivide

Попытка деления на ноль

EOverflow

Переполнение с плавающей точкой

EUnderflow

Исчезновение порядка

EInvalidArgument

Неверный аргумент математических функций

Для этого используется оператор raise, за которым в качестве параметра должен идти экземпляр объекта типа Exception. Обычно сразу за оператором следует конструктор класса ИС:

raise EMathError.Create(' ') ;

но можно и разделить создание и возбуждение исключительной ситуации:

var E: EMathError

begin

E := EMathError.Create С');

raise E; 

end;

Оператор raise передает созданную исключительную ситуацию ближайшему блоку try. .except (см. ниже).

if С = 0 then

raise EDivByZero.Create('Деление на ноль')

else

А := В/С;

Самостоятельная инициализация ИС может пригодиться при программировании реакции приложения на ввод данных, для контроля значений переменных и т. д. В таких случаях желательно создавать собственные классы ИС, специально приспособленные для ваших нужд. Также полезно использовать специально спроектированные исключительные ситуации при создании собственных объектов и компонентов. Так, многие важнейшие классы VCL — списки, потоки, графические объекты — сигнализируют о своих (или ваших?) проблемах созданием соответствующей ИС — EListError, EInvalidGraphic, EPrinter и т. д.

Самый важный отличительный признак объекта Exception — это все же класс, к которому он принадлежит. Именно факт принадлежности возникшей ИС к тому или иному классу говорит о том, что случилось. Если же нужно детализировать проблему, можно присвоить значение свойству Message. Если и этого мало, можно добавить в объект новые поля. Так, в ИС EinOutError (ошибка ввода/вывода) есть поле ErrorCode, значение которого соответствует произошедшей ошибке — запрету записи, отсутствию или повреждению файла и т. д.

try

.FileOpenС с:\myfile.txt', fmOpenWrite); 

except

on E: EinOutError do

 case E.ErrorCode of

ERROR_FILE_NOT_FOUND {=2}: ShowMessage('Файл не найден !');

 ERROR_ACCESS_DENIED {=5}: ShowMessage('Доступ запрещен!'); 

ERROR_DISK_FULL {=112}: ShowMessage ('Диск переполнен!') ;

 end;

  end;

Впрочем, ИС EInOutError возникают только тогда, когда установлена опция компилятора {$IOCHECKS ON} (или иначе {$I+}). В противном случае проверку переменной IOResult (известной еще по Turbo Pascal) нужно делать самому.

Еще более "продвинутый" пример — ИС EDBEngineError. Она имеет свойства ErrorCount и свойство-массив Errors: одна операция с базой данных может породить сразу несколько ошибок.

Защитные конструкции языка Object Pascal

Для работы с объектами исключительных ситуаций существуют специальные конструкции языка Object Pascal— блоки try., except и try. .finally. Они контролируют выполнение операторов, помещенных внутри блока до ключевого слова except или finally. В случае возникновения исключительной ситуации штатное выполнение вашей программы немедленно прекращается, и управление передается операторам, идущим за указанными ключевыми словами. Если в вашей процедуре эти блоки отсутствуют, управление все равно будет передано ближайшему блоку, внутри которого возникла ситуация. А уж внутри VCL их предостаточно.

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

Блок try..Except

Для реакции на конкретный тип ситуации применяется блок try..except. Синтаксис его следующий:

try

<Оператор>

 <Оператор>

...

except

on EExceptionl do < Оператор обработки ИС типа EExceptionl >;

on EException2 do < Оператор >;

...

else { }

<0ператор> {обработчик прочих ИС}

  end;

Выполнение блока начинается с секции try. При отсутствии исключительных ситуаций только она и выполняется. Секция except получает управление в случае возникновения ИС. После обработки происходит выход из защищенного блока, и управление обратно в секцию try не передается; выполняются операторы, стоящие после end.

Если вы хотите обработать любую ИС одинаково, независимо от ее класса, вы можете писать код прямо между операторами except и end. Но если обработка отличается, здесь можно применять набор директив on. .do, определяющих реакцию приложения на определенную ситуацию. Каждая директива связывает ситуацию (on...), заданную своим именем класса, с группой операторов (do...).

U := 220.0; 

R := 0;

 try

I := U / R; 

except

on EZeroDivide do MessageBox('Короткое замыкание!');

  end;

В этом примере замена if. .then на try. .except, может быть, не дала очевидной экономии кода. Однако если при решении, допустим, вычислительной задачи проверять на возможное деление на ноль приходится не один, а множество раз, то выигрыш от нового подхода неоспорим — достаточно одного блока try. .except на все вычисления.

При возникновении ИС директивы просматриваются последовательно, в порядке их описания. Каждый тип исключительной ситуации, описанный после ключевого слова on, обрабатывается именно этим блоком: только то, что предусмотрено в нем, и будет являться реакцией на данную ситуацию.

(рис. 3.2).

Рис. 3.2. Типовое окно сообщения об ошибке Для этого нужно вызвать процедуру

procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);

имеющуюся в модуле SYSUTILS.PAS.

Если предусмотренной вами обработки ИС недостаточно, то можно продолжить ее дальше программно при помощи оператора raise.

Этот оператор уже встречался нам при описании создания пользовательских ИС. Там за ним следовал вызов конструктора ИС. Здесь же конструктор опущен: возбуждаться будет уже существующий объект ИС, приведший нас в блок:

...

sl:= TStringList. Create;

try

s1.LoadFromFile(AFileName); 

except

sl.Free; 

raise;

 end;

...

В этом примере в случае возникновения исключительной ситуации созданный список строк должен быть уничтожен. Сама же обработка предоставляется "вышестоящим инстанциям".

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]