На этом шаге мы рассмотрим пример использования рассмотренных блоков.
Для демонстрации использования оператора обработки исключительных ситуаций приведем следующий пример.
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Label6: TLabel; Label7: TLabel; Memo1: TMemo; Edit5: TEdit; Button1: TButton; Edit6: TEdit; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label8: TLabel; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} var Switch:Integer; {Счетчик Switch изменяет свое значение по циклу от 1 до 4 } {и выполняет переключение между четырьмя демонстрационными } {примерами по щелчку на кнопке "Следующий пример" } function GetCodeName(V : Variant): String; { Функция возвращает идентификатор кода вариантного типа} type TypeCodeNames = array [$0000..$000D] of String; const CodeNames: TypeCodeNames = ('varEmpty','varNull','varSmallint','varInteger', 'varSingle','varDouble', 'varCurrency','varDate', 'varOleStr','varDispatch','varError','varBoolean', 'varVariant','varUnknown'); var Code : Integer; begin Code := VarType(V) and varTypeMask; case Code of $0000..$000D: Result:= CodeNames[Code]; $0011: Result:='varByte'; $0100: Result:='varString'; $0FFF: Result:='varTypeMask'; $2000: Result:='varArray'; else Result :='varError'; end; end; procedure TForm1.Button1Click(Sender: TObject); var Op1, Op2 : Variant; Integer1,Integer2 : Integer; Double1, Double2 : Double; Currency1, Currency2 : Currency; TDateTime1, TDateTime2 : TDateTime; procedure PrintOperands (Op1, Op2: Variant); { Процедура печатает идентификаторы кодов операндов } { вариантного типа и значения этих операндо в заданных} { полях Edit1, Edit2, Edit3 и Edit4.} var CodeName, S : String; begin CodeName := GetCodeName(Op1); Edit1.Text := CodeName; if CodeName <> 'varString' then Str(Op1:10:4, S) else S := Op1; Edit2.Text := S; CodeName := GetCodeName(Op2); Edit3.Text := CodeName; if CodeName <> 'varString' then Str(Op2:10:4, S) else S := Op2; Edit4.Text := S; end; procedure Action1 (Op1,Op2: Variant); {Процедура Actionl печатает текст своих операторов в поле } {Memol, выполняет операции сложения и деления над заданными } {операндами Opl и Oр2 вариантного типа, а также выводит } {результаты этих операций в диалоговых окнах. В случае } {возникновения исключительной ситуации EVariantError } {сообщает об этом в диалоговом окне. При возникновении } {любых других исключений выводит сообщение "Ошибка } { времени выполнения". } var Res : Variant; S : String; begin try { Вывод текста своих операторов в поле Memol. } Memo1.Lines[0]:='try'; Memo1.Lines[1]:=' Res := Op1 + 0p2;'; Memo1.Lines[2]:=' Str (Res:10:4, S);'; Memo1.Lines[3]:=' MessageDlg(''Op1 + Op2 = ''+S, '+ 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[4]:=' Res := Op1 / Op2;'; Memo1.Lines[5]:=' Str (Res:10:4, S);'; Memo1.Lines[6]:=' MessageDlg(''Op1 / Op2 = ''+S, ' + 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[7]:='except'; Memo1.Lines[8]:=' on EVariantError do'; Memo1.Lines[9]:=' MessageDlg(''Ошибка EVariantError'', '+ 'mtError,[mbOk],0);'; Memo1.Lines[10]:=' else'; Memo1.Lines[11]:=' MessageDlg(''Ошибка времени '+ 'выполнения'' , mtError, [mbOK] , 0); ' ; Memo1.Lines[12]:='end;'; Edit6.Text:='+'; Res := Op1 + Op2; Str (Res:10:4, S); MessageDlg('Op1 + Op2 = '+S, mtInformation,[mbOk],0); Edit6.Text:='/'; Res := Op1 / Op2; Str (Res:10:4, S); MessageDlg('Op1 / Op2 = '+S, mtInformation,[mbOk],0); except on EVariantError do MessageDlg('Ошибка EVariantError', mtError,[mbOk],0); else MessageDlg('Ошибка времени выполнения', mtError,[mbOk],0); end; end; procedure Action2 (Op1,Op2: Variant); {Работает аналогично процедуре Actionl, но при возникно- } {вении любой исключительной ситуации выводит одно и то же } { сообщение "Какая-то ошибка времени выполнения". } var Res : Variant; S : String; begin try { Вывод текста своих операторов в поле Memol. } Memo1.Lines[0]:='try'; Memo1.Lines[1]:=' Res := Op1 + 0p2;'; Memo1.Lines[2]:=' Str (Res:10:4, S);'; Memo1.Lines[3]:=' MessageDlg(''Op1 + Op2 = ''+S, '+ 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[4]:=' Res := Op1 / Op2;'; Memo1.Lines[5]:=' Str (Res:10:4, S);'; Memo1.Lines[6]:=' MessageDlg(''Op1 / Op2 = ''+S, ' + 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[7]:='except'; Memo1.Lines[8]:=' MessageDlg(''Какая-то ошибка времени '+ 'выполнения'' , mtError, [mbOK] , 0); ' ; Memo1.Lines[9]:='end;'; Edit6.Text:='+'; Res := Op1 + Op2; Str (Res:10:4, S); MessageDlg('Op1 + Op2 = '+S, mtInformation,[mbOk],0); Edit6.Text:='/'; Res := Op1 / Op2; Str (Res:10:4, S); MessageDlg('Op1 / Op2 = '+S, mtInformation,[mbOk],0); except MessageDlg('Какая-то ошибка времени выполнения', mtError,[mbOk],0); end; end; procedure Action3 (Op1,Op2: Variant); {По структуре аналогична процедуре Action2, но демонстри- } {рует обработку исключительных ситуаций с помощью блока } {try. . . finally. Сообщение "Обработка блока операторов } {finally" будет появляться как нормальном выполнении } {операции деления, так и при возникновении любой } {исключительной ситуации. } var Res : Variant; S : String; begin try { Вывод текста своих операторов в поле Memol. } Memo1.Lines[0]:='try'; Memo1.Lines[1]:=' Res := Op1 / Op2;'; Memo1.Lines[2]:=' Str (Res:10:4, S);'; Memo1.Lines[3]:=' MessageDlg(''Opl / Op2 = ''+S, ' + 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[4]:='finally'; Memo1.Lines[5]:=' MessageDlg(''Обработка блока операторов '+ 'finally'' , mtInformation, [mbOK] , 0); ' ; Memo1.Lines[6]:='end;'; Edit6.Text:='/'; Res := Op1 / Op2; Str (Res:10:4, S); MessageDlg('Opl / Op2 = '+S, mtInformation,[mbOk],0); finally MessageDlg('Обработка блока операторов finally', mtInformation,[mbOk],0); end; end; procedure Action4 (Op1,Op2: Variant); {По структуре аналогична процедуре Action2, но демонстри- } {рует обработку исключительных ситуаций с помощью вложенных } {блоков try try ... except ... end; finally ... end. } { Сообщение "Обработка блока операторов finally" будет } { появляться как нормальном выполнении операции деления, } { так и после обработки любой исключительной ситуации при } { ее возникновении. } var Res : Variant; S : String; begin try try { Вывод текста своих операторов в поле Memol. } Memo1.Lines[0]:='try'; Memo1.Lines[1]:=' try'; Memo1.Lines[2]:=' Res := Op1 / Op2;'; Memo1.Lines[3]:=' Str (Res:10:4, S);'; Memo1.Lines[4]:=' MessageDlg(''Op1 / Op2 = ''+S, ' + 'mtlnformation,[mbOk],0) ; ' ; Memo1.Lines[5]:='except'; Memo1.Lines[6]:=' MessageDlg(''Какая-то ошибка времени '+ 'выполнения'' , mtError, [mbOK] , 0); ' ; Memo1.Lines[7]:='end;'; Memo1.Lines[8]:='finally'; Memo1.Lines[9]:=' MessageDlg(''Обработка блока операторов '+ 'finally'' , mtInformation, [mbOK] , 0); ' ; Memo1.Lines[10]:='end;'; Edit6.Text:='/'; Res := Op1 / Op2; Str (Res:10:4, S); MessageDlg('Op1 / Op2 = '+S, mtInformation,[mbOk],0); except MessageDlg('Какая-то ошибка времени выполнения', mtError,[mbOk],0); end; finally MessageDlg('Обработка блока операторов finally', mtInformation,[mbOk],0); end; end; begin {TForm1.Button1Click} case Switch of 1: begin Inc(Switch); Form1.Caption := 'Блок try. ..except on...do...else...end'; { Исходные данные для работы без ошибки. } Edit5.Text:= 'Работа try...except on...do...else...end,'+ ' если ошибки не было'; Op1 := 4; Op2 := 2; PrintOperands (Op1, Op2); Action1(Op1, Op2); { Исходные данные для работы с ошибкой EVariantError. } Edit5.Text:='Работа try...except on...do...else...end,'+ ' если была ошибка EVariantError'; Op1 := 4; Op2 := 'A'; PrintOperands (Op1, Op2); Action1(Op1, Op2); { Исходные данные для работы с другой ошибкой } { (деления на нуль). } Edit5.Text:='Работа try...except on...do...else...end,' + ' если была другая ошибка '; Op1 := 4; Op2 := 0; PrintOperands (Op1, Op2); Action1(Op1, Op2); end; 2: begin Inc(Switch); Form1.Caption :='Блок try...except...end'; { Исходные данные для работы без ошибки. } Edit5.Text:='Работа try...except...end,'+ ' если ошибки не было'; Op1 := 4; Op2 := 2; PrintOperands (Op1, Op2); Action2(Op1, Op2); { Исходные данные для работы с ошибкой EVariantError. } Edit5.Text:='Работа try...except...end,'+ ' если была ошибка EVariantError'; Op1 := 4; Op2 := 'A'; PrintOperands (Op1, Op2); Action2(Op1, Op2); { Исходные данные для работы с другой ошибкой } { (деления на нуль). } Edit5.Text:='Работа try...except...end,'+ ' если была другая ошибка '; Op1 := 4; Op2 := 0; PrintOperands (Op1, Op2); Action2(Op1, Op2); end; 3: begin Inc(Switch); Form1.Caption :='Блок try...finally...end'; { Исходные данные для работы без ошибки. } Edit5.Text:='Работа try...finally...end,'+ ' если ошибки не было'; Op1 := 4; Op2 := 2; PrintOperands (Op1, Op2); Action3(Op1, Op2); { Исходные данные для работы с ошибкой (деление на нуль). } Edit5.Text:='Работа try...finally...end,'+ ' если была какая-либо ошибка'; Op1 := 4; Op2 := 0; PrintOperands (Op1, Op2); Action3(Op1, Op2); end; 4: begin Switch:=1; Form1.Caption :='Блок try try...except...end; finally... end'; { Исходные данные для работы без ошибки. } Edit5.Text:= 'Работа try try. ..except...end;' + ' finally...end, если ошибки не было'; Op1 := 4; Op2 := 2; PrintOperands (Op1, Op2); Action4(Op1, Op2); { Исходные данные для работы с ошибкой (деление на нуль). } Edit5.Text:= 'Работа try try...except...end; ' + 'finally...end, если была какая-либо ошибка'; Op1 := 4; Op2 := 0; PrintOperands (Op1, Op2); Action4(Op1, Op2); end; end; {case} end; {TForm1.Button1Click} procedure TForm1.FormCreate(Sender: TObject); var i:Byte; begin for i:=0 to 12 do Memo1.Lines.Add(' '); Form1.Caption := 'Оператор try' ; end; initialization Switch:=1; end.
После старта проекта, использующего приведенный модуль, при щелчке на кнопке "Следующий пример" будут поочередно запускаться четыре примера, демонстрирующие рассмотренные в шагах 75 - 78 варианты блоков обработки исключительных ситуаций. Однако прежде, чем запускать этот проект, необходимо обратить внимание на следующее.
Рис.1. Отключение опции
В противном случае, при возникновении исключительных ситуаций будут появляться системные сообщения об ошибках времени выполнения для всех исключений, невзирая на то, выполняется ли обработка данного исключения операторами try, или нет.
Приведем сокращенный протокол работы этого проекта с комментариями. После старта проекта и щелчка на кнопке "Следующий пример" выполняются операторы первого примера по альтернативе оператора case при Switch=l (см. операторы метода TForm1.Button1Click). Первый вызов процедуры Action1 с корректными исходными данными отрабатывает нормально, показывая на экране диалоговые окна с резулътатами выполнения операций + и /. При втором вызове процедуры Action1 форма проекта принимает следующий вид:
Рис.2. Ошибка EVariantError
Как видно, процедуре Action1 передаются фактические параметры, при обработке которых возникает исключительная ситуация EVariantError. Поэтому при выполнении первой же операции сложения управление передается в блок обработки исключений, на экране появляется соответствующее диалоговое окно с сообщением об ошибке (рисунок 2) и работа процедуры Action1 заканчивается, не дойдя до операции деления.
При третьем вызове Action1 моделируется ситуация деления на нуль:
Рис.3. Ошибка при делении на нуль
В блоке exception нет отдельной конструкции on...do, обращающей именно такие исключения, поэтому будут выполняться операторы альтернативы else.
На этом первый пример заканчивается и для запуска второго требуется щелкнуть на кнопке "Следующий пример". Во втором примере (Switch=2) аналогично первому выполняется три вызова процедуры Action2, в которой демонстрируется работа сокращенного варианта блока обработки исключений вида try...except...end без конструкций on...do. Первый, корректный, вызов Action2 отрабатывает также, как и в предыдущем примере. При втором вызове Action2 форма проекта будет иметь такой вид:
Рис.4. Вторая форма
Второй и третий вызовы Action2 моделируют такие же исключения, как и при вызове Action1. Однако в Action2 все исключительные ситуации будут обрабатываться одинаково. В результате при втором запуске Action2 появится диалоговое окно, изображенное на рисунке 4.
После очередного щелчка на кнопке "Следующий пример" запускается третий пример (Switch=3), демонстрирующий работу блока обработки исключений вида try...finally...end. Операторы, стоящие после зарезервированного слова finally, будут выполняться как в случае отсутствия исключений, так и в случае их возникновения. Поэтому при корректных исходных данных для процедуры Action3 последовательно получим на экране такие диалоговые окна:
Рис.5. Диалоговые окна
При втором вызове Action3, когда моделируется исключение типа деления на нуль, форма проекта примет вид:
Рис.6. Деление на нуль
В случаях, если требуется выполнить группу заключительных операторов с помощью блока try...finally...end и одновременно подавить системную реакцию на исключения, используются вложенные и обработки исключительных ситуаций вида:
try try . . . except . . . end; finally . . . end;
try try . . . finally . . . end; except . . . end;
Работа вложенного блока первого из приведенных вида демонстрируется в четвертом примере (Switch=4) рассматриваемого проекта. В этом примере дважды вызывается процедура Action4, которая содержит такие же операторы, как и процедура Action3, но, в отличие от последней, расположенные внутри вложенного блока обработки исключений. При этом передаваемые процедуре параметры моделируют такие же ситуации, как и в третьем примере. Первый вызов Action4 с корректными для операции деления данными отрабатывает идентично первому вызову Action3. А после второго вызова Action4, когда форма проекта будет иметь вид:
Рис.7. Четвертый вариант с первым из диалоговых окон
на экране появятся последовательно такие диалоговые окна (первое - на рисунке 7):
Рис.8. Второе диалоговое окно
Как видно из полученных результатов, вместо системного сообщения "Floating point division by zero" на экране отображается диалоговое окно с сообщением "Какая-то ошибка времени выполнения", которое выводится операторами блока except. Кроме того, поскольку блок except располагается внутри блока finally, то сообщение об ошибке появится перед сообщением "Обработка блока операторов finally", а не наоборот, как в третьем примере.
На следующем шаге мы рассмотрим принудительное возбуждение исключительных ситуаций.