Блок try…except имеет следущий вид:
Оператор try..except

Если исключение не инициируется во время выполнения списка операторов, то все операторы в списке будут выполняться последовательно до end, за исключением блока except, который будет пропущен,
Если исключение происходит во время выполнения списка операторов, поток выполнения будет прерван и управление будет передано на except блок. Операторы между местом, где произошло исключение и до блока except — игнорируются.
В блоке обработки исключения, проверяется объект исключения, и если есть обработчик исключения, данного типа (класса) или родительского класса объекта исключения, то выполняются операторы после соответствующего do. Используется первый же подходящий объект, данного класса. После того , как блок — do был выполнен, программа продолжается c конца блока (служебное слово end).
Идентификатор (имя, после служебного слова on) в операторе обработки исключений не является обязательным, и если он есть, то он объявляет объект исключения (можно указать имя объекта, а можно только его тип). Он может быть использован для манипуляций с объектом исключения в коде обработки исключений. То, как организует программист блок после слова do, зависит от его потребностей.
Если ни один из обработчиков on не соответствует типу объекта исключения, то выполняется список операторов после else. Если этот список не найден (отсутствует сл. слово else), то обработка исключения передаётся на более высокий уровень (неявный raise). Этот процесс позволяет обрабатывать только некоторые исключения (указанные в блоке try…except).
Если исключение начало обрабатываться, то объект исключения автоматически разрушается вызовом деструктора destroy (самому вызывть ненадо) и упрвление передается инструкции, следующей за блоком try…except. (Если вызов стандартных процедур Exit, Break или Continue выводит управление из обработчика, объект исключения также разрушается).
В качестве примера, рассмотрим предыдущую функцию DoDiv (из предыдущего примера):
Try
Z := DoDiv (X,Y);
Except
On EDivException do Z := 0;
end;
Если Y будет равным нулю, то код функции DoDiv вызовет исключение. Когда это произойдёт, будет создано исключение, и его обработчик установит Z значение 0. Если исключение не происходит, то программа выполнится, игнорируя блок except. Для того, что-бы применить восстановление после ошибки, нужно использовать блок. Блок try…finally, гарантирует, что будут выполнены операторы после сл. слова finally, даже если произойдёт исключение.
|
Sharpix 6 / 6 / 0 Регистрация: 07.10.2013 Сообщений: 93 |
||||
|
1 |
||||
|
19.09.2016, 22:39. Показов 12870. Ответов 1 Метки exception, finally, lazarus, try except, try except finally, try exception, try finally, исключения, лазарус, научите, обработка исключений, отладка, try/catch (Все метки)
Здравствуйте. Научите меня правильно использовать обработку исключений на примере деления на ноль. Добавил просто блок try-except — оно не работает. Не нашел в интернете ни одного рабочего примера.
__________________
0 |
|
BOGG ART 587 / 454 / 147 Регистрация: 09.12.2013 Сообщений: 2,385 Записей в блоге: 2 |
||||||||
|
19.09.2016, 23:54 |
2 |
|||||||
|
Что в вашем понимании «не работает»? Отладка выскакивает? Ну так и должно быть по умолчанию. В настройках отключите. Или запускайте не из под IDE. Добавлено через 1 минуту
Добавлено через 8 минут
1 |
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
но возникновение исключений. После except следуют операторы, которые образуют секцию обработки исключений. Признаком конца секции служит ключевое слово end. Внутри секции программист указывает классы исключе-
ний (говорят еще типы исключений) после слова on, а затем после ключевого слова do оператор обработки исключения, причем оператор может быть со-
ставным. После необязательного else следуют операторы обработки исклю-
чений, не вошедшие в перечень on. Если программисту нужно только устано-
вить сам факт исключения, независимо от типа, то он может просто записать обработчик исключения после слова except.
Вторая конструкция имеет вид:
try
<Потенциально «опасные» операторы, при выполнении которых могут возникнуть исключительные ситуации >
finally
<операторы, которые должны быть выполнены в любом случае, незави-
симо от того, произошло исключение или нет >
end;
В чем их различие? В конструкции try..except если при выполнении операторов секции try возникло исключение, то управление передается в сек-
цию except, где и происходит обработка исключения. Если же исключения не произошло, то операторы блока except просто пропускаются. В конструкции try..finally операторы будут выполнены независимо от того, произошло исключение или нет.
Рассмотрим пример:
try
num:=StrToInt(Stroka);
521
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
except
on EConvertError do
ShowMessage(‘Ошибка преобразования строки в целое число‘);
end;
Здесь сообщение будет выведено только в том случае, когда невозможно преобразование строки символов в целое число, то есть когда возникнет ис-
ключение EConvertError.
Конструкции try..except и try..finally могут быть вложены друг в друга на неограниченную глубину. Рассмотрим реализацию примера с файлом.
Procedure Test; var
F: TextFile; number: integer; s: string;
begin
AssignFile(F, ‘Data.txt’);
Rewrite(F);
|
s:= ’12#4′; |
// В файл намеренно записывается |
|
|
Writeln(F, s); |
// ошибочная строка символов |
|
|
Reset(F); |
||
|
try |
// начало секции (блока) try..except |
|
|
Readln(F, s); |
||
|
try |
// начало секции try..finally |
number:= StrToInt(s);
finally
CloseFile(F); // эти два оператора будут выполнены
522
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
DeleteFile(‘Data.txt’); // в любом случае
end; // конец секции try..finally
except
on EConvertError do
ShowMessage(‘Ошибка преобразования’); end; // конец секции try..except
end;
Вернемся к примеру, в котором осуществляется ввод двух целых чисел и выполняются четыре арифметических действия (сложение, вычитание, умно-
жение и деление нацело), рис. 6.30. Модифицируем программу, добавив в него обработку исключений. Перепишите обработчики события OnKeyPress для
LabeledEdit1 и событий OnClick кнопок SpeedButton1, SpeedButton2, SpeedButton3 и SpeedButton4 в виде:
procedure TForm1.LabeledEdit1KeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then begin
try StrToInt(LabeledEdit1.Text);
except
on EConvertError do begin
ShowMessage(‘Ошибка преобразования! Вероятно, ‘ +
‘Вы ошиблись при вводе числа‘);
exit;
end;
523
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
end;
LabeledEdit2.SetFocus; SpeedButton1.Down:= false; SpeedButton2.Down:= false; SpeedButton3.Down:= false; SpeedButton4.Down:= false; exit;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
+ StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage(‘Ошибка преобразования! Вероятно, ‘ + ‘Вы ошиблись при вводе второго числа‘);
exit;
end;
end;
StatusBar1.SimpleText:= ‘Сложение‘;
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
524
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
begin try
LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
— StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage(‘Ошибка преобразования! Вероятно, ‘ + ‘Вы ошиблись при вводе второго числа‘);
exit;
end;
end;
StatusBar1.SimpleText:= ‘Вычитание‘;
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
* StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage(‘Ошибка преобразования! Вероятно, ‘ +
‘Вы ошиблись при вводе второго числа‘);
exit;
end;
525
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
end;
StatusBar1.SimpleText:= ‘Умножение‘;
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
procedure TForm1.SpeedButton4Click(Sender: TObject); begin
try LabeledEdit3.Text:=IntToStr(StrToInt(LabeledEdit1.Text)
div StrToInt(LabeledEdit2.Text));
except
on EConvertError do begin
ShowMessage(‘Ошибка преобразования! Вероятно, ‘ + ‘Вы ошиблись при вводе второго числа‘);
exit;
end;
on EDivByZero do begin
ShowMessage(‘Ошибка! Произошло деление на ноль. Вероятно, ‘ + ‘Вы ошиблись при вводе второго числа‘);
exit;
end;
end;
StatusBar1.SimpleText:= ‘Деление нацело‘;
LabeledEdit1.SetFocus;
LabeledEdit1.SelectAll;
end;
526
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
Теперь при вводе недопустимого символа для целого числа, а также при вводе числа 0 в качестве второго операнда программа перехватывает исключе-
ния и реагирует соответствующим образом.
Имейте в виду, если вы запускаете программу из среды Lazarus, то исклю-
чения будет перехватывать отладчик. Поэтому лучше запускать программу из командной строки или в настройках окружения для отладчика добавьте нужные вам типы исключений в список игнорирования.
Обработку исключений вполне можно применять и в консольных прило-
жениях. Вспомним программу из 2.1.14. Организуем контроль ввода данных,
используя механизм исключений.
program int_operations_control; {$mode objfpc}{$H+}
uses
CRT, FileUtil, SysUtils; var
A, B, C: integer; begin
writeln(UTF8ToConsole(‘Введите два числа‘)); readln(A, B);
writeln(‘A= ‘, A, ‘ B= ‘, B); C:= A + B;
writeln(UTF8ToConsole(‘Демонстрация сложения, C= ‘), C); C:= A * B;
writeln(UTF8ToConsole(‘Демонстрация умножения, C= ‘), C); try
C:= A div B;
writeln(UTF8ToConsole(‘Демонстрация деления нацело, C= ‘),
C);
527
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
except
on EDivByZero do begin
writeln(UTF8ToConsole(‘Ошибка!! Деление на ноль.‘)); writeln(UTF8ToConsole(‘Нажмите любую клавишу‘)); readkey;
exit;
end;
end;
C:= A mod B;
writeln(UTF8ToConsole(‘Остаток от деления, C= ‘), C); C:= A — B;
writeln(UTF8ToConsole(‘Демонстрация вычитания, C= ‘), C); writeln(UTF8ToConsole(‘Нажмите любую клавишу‘)); readkey;
end.
Сравните эту программу с программой из 2.1.25.
Контроль и обработку ошибок с применением механизма исключений удобнее использовать, когда работа программы уже не зависит от действий пользователя, т.е. все необходимые данные от пользователя уже получены,
программа перешла непосредственно к обработке данных – идут вычисления,
происходит чтение и запись в файлы, обращения к различным внешним уст-
ройствам и т.д. На этапе же ввода данных, когда пользователь в режиме диало-
га вводит какие-то данные с клавиатуры, удобнее использовать другой способ контроля. Поскольку обработка исключений происходит после завершения ввода пользователем, то есть этим происходит только констатация факта, что ошибка пользователем уже совершена. Приходится организовывать повторный ввод, причем с того места, где пользователь ошибся. А это приведет к усложне-
528
Глава 6 Программирование приложений с графическим интерфейсом
____________________________________________________________________
нию кода. Гораздо разумнее и эффективней при вводе данных просто не давать пользователю совершить ошибку. Например, если пользователь должен вво-
дить только целые числа, проще контролировать введенные пользователем символы и, если будет попытка ввести недопустимый для целых чисел символ,
просто этот символ игнорировать.
Для этого удобнее использовать другую разновидность компонента TEdit
– TMaskEdit из страницы Additional.
6.3.7.1. Компонент TMaskEdit
В этом компоненте имеется свойство EditMask, с помощью которого можно задать маску ввода. Маска это некий шаблон, задающий какие символы может вводить пользователь в окне ввода. Недопустимые символы игнориру-
ются. Маска состоит из трех частей, между которыми ставится точка с запятой
(;). В первой части маски – шаблоне записываются символы (табл. 6.2), кото-
рые указывают какие символы можно вводить в каждой позиции.
Таблица 6.2
Означает, что в EditText недостающие символы предваряются
!пробелами. В случае отсутствия символа пробелы размещаются в конце.
0 Означает, что в данной позиции должна быть цифра.
9 Означает, что в данной позиции может быть цифра или ничего.
#Означает, что в данной позиции может быть цифра, знак « + », знак «-» или ничего.
Далее через точку с запятой (;) записывается 1 или 0 в зависимости от того,
надо или нет, чтобы символы, добавляемые маской, включались в свойство
Text компонента. В третьей части маски указывается символ-заполнитель, ис-
пользуемый для обозначения позиций, в которых еще не осуществлен ввод. Ус-
тановить нужную маску можно прямо в свойстве EditMask, введя необходи-
мые символы маски или в редакторе масок, открыть который можно нажав
529
6.3 Визуальное программирование в среде Lazarus
____________________________________________________________________
кнопку с троеточием, рис. 6.33.
Рис. 6.33. Окно редактора масок
Прочитать результат ввода можно или в свойстве Text, которое, в зависи-
мости от вида второй части маски, включает или не включает в себя символы маски, или в свойстве EditText, содержащем введенный текст вместе с сим-
волами маски.
Итак, давайте применим для нашего примера компонент TMaskEdit.
Удалите из формы LabeledEdit1 и LabeledEdit2. Перенесите на их ме-
сто два компонента TMaskEdit. Также вставьте в форму два компонента
TLabel. В общем, восстановите внешний вид формы как на рисунке 6.30.
Установите следующие свойства MaskEdit1:
AutoSelect = true
EditMask = #9999;0;
TabOrder = 0
свойство Text оставьте пустым.
В качестве символа заполнителя в окошке «Символы для пробелов» в ре-
дакторе масок введите пробел вместо знака подчеркивания.
Установите свойства MaskEdit2:
530
В процессе выполнения скрипта возможно возникновение исключительных ситуаций, ошибок. Если это происходит, то пользователь видит сообщение об ошибке «Опа!…». Вы можете перехватить ошибку и обработать ее особым образом. Для обработки исключительных ситуаций блок кода, в котором они возможны, заключается в составной оператор try.
try FS := TFileStream.Create(MyFileName, fmCreate); except MsgBox(‘Ошибка’, ExceptionToString(ExceptionType, ExceptionParam); end;
Если в блоке try происходит исключение, то выполнение кода прерывается и выполняется код в блоке except.
Есть другая конструкция – try..finally:
try FS := TFileStream.Create(MyFileName, fmCreate); try … finally FS.Free; end; except MsgBox(‘Ошибка’, ExceptionToString(ExceptionType, ExceptionParam); end;
Код в блоке finally выполняется в любом случае, нормально ли отработал код или произошла ошибка. Если в блоке try используется ключевое слово exit (выход из процедуры/функции), то код в блоке finally также выполняется.
В операторе try могут быть использованы оба блока:
try … except … finally … end;
Вы можете программно сгенерировать исключение, используя процедуру RaiseException:
var filename, emsg: string; begin filename = ''; try if filename = '' then RaiseException(erCustomError, 'Имя файла не может быть пустым'); … except emsg := ExceptionToString(ExceptionType, ExceptionParam); … end; end;
При обработке исключительных ситуаций могут быть использованы следующие процедуры и функции:
function ExceptionToString(Err: TIFException; Param: String): String
Формирует по типу исключения строку сообщения об ошибке.
function ExceptionType: TIFException
Возвращает тип возникшего исключения.
function ExceptionParam: String
Возвращает текст сообщения об ошибке.
procedure RaiseException(Err: TIFException; Param: String)
Генерирует исключительную ситуацию.
procedure RaiseLastException
Генерирует последнюю возникшую исключительную ситуацию.

Как узнать код ошибки try except
- Подписаться на тему
- Сообщить другу
- Скачать/распечатать тему
|
|
|
|
Senior Member
Рейтинг (т): 3 |
Подскажите, можно ли как нибудь отловить код ошибки?
//readln(A); =0; try Z:=Z/A; except on E: exception do ShowMessage(e.messages); end; Ну это конечно ясно, что он напишет ‘Division by zero’, но это во-первых по английски, а во вторых, если мы напишем сразу сообщение по русски, т.е. так:
//readln(A); =0; try Z:=Z/A; except ShowMessage(‘Деление на ноль!’); end;
и допустим, что ошибка произошла не из-за того, что делится на ноль, а из-за чего-нибудь другова — то естественно сообщение будет ложным, а точнее неверным.
//readln(A); =0; try Z:=Z/A; except on E: exception do if (e.messages=’Division by zero’) then ShowMessage(‘Деление на ноль’) else ShowMessage(e.messages); end;
Почему вариант тупой, да потому что, перед тем как вставить текст сообщения об ошибке надо: Хочется что-то типа того, что текст ошибки сообщения мог бы заменять какой-нибудь её индетификатор, чтобы можно было типа такого:
//readln(A); =0; try Z:=Z/A; except on E: exception do if (e.код_ошибки=123) then ShowMessage(‘Деление на ноль’) else ShowMessage(e.messages); end; где «123» есть индетификатор ошибки, т.е. заменяет сам текст ‘Division by zero’. Да, и у e нет параметра на английском, что я написал на русском код_ошибки. Ууууу…. Пока писал — сам устал. |
|
CodeMonkey |
|
|
on E: EDivByZero do Подробно и в деталях. |
|
Continental |
|
|
Senior Member
Рейтинг (т): 3 |
Спасибо за ссылку.
except on E: EIBInterBaseError do begin sShowMessage(e.ClassName,e.Message); exit; end; а он мне пишет: Неизвестная переменная EIBInterBaseError Вообще класс такой есть, он даже его показывает, если я делаю так:
try Connected:=true; except on E: exception do sShowMessage(e.ClassName,e.Message); end; Вот e.ClassName как раз и есть EIBInterBaseError, только я не могу класс коде указать. Сообщение отредактировано: Continental — 27.10.09, 14:48 |
|
mitrich |
|
|
Senior Member
Рейтинг (т): 99 |
Хелп говорит, что EIBInterBaseError находится в юните IB |
|
CodeMonkey |
|
|
Цитата Continental @ 27.10.09, 14:21 А вот в каком модуле находятся классы исключений при работе с ibx компонентами.
Пуск/Поиск. *.pas с текстом EIBInterBaseError. Цитата Continental @ 27.10.09, 14:21 Вообще класс такой есть, он даже его показывает, если я делаю так Вместо
except on E: SomeClass do … можно (но не рекомендуется) использовать:
except on E: Exception do if E.ClassName = ‘SomeClass’ then … else raise; |
|
Continental |
|
|
Senior Member
Рейтинг (т): 3 |
ММММ…. всё равно прочитав всё, не могу реализовать то что я хочу. Так вот я хочу сказать, что в двух случаях ошибки совсем разные, а вот класс исключения один и тот же.
try IBDataBase.Connected:=true; except on E : что здесь должно быть, чтобы определить 1-й случай? do begin sShowMessage(‘несуществующий путь бд!’); exit; end; on E : что здесь должно быть, чтобы определить 2-й случай? do begin sShowMessage(‘неверный пользователь или пароль’); exit; end; on E : Exception do begin //люая другая ошибка sShowMessage(e.ClassName,E.Message+’ совершенно другая ошибка’); exit; end; end; Помогите разобраться пожалуйста, я очень хочу сделать так, но не знаю. |
|
CodeMonkey |
|
|
Цитата Continental @ 27.10.09, 15:51 Так вот я хочу сказать, что в двух случаях ошибки совсем разные, а вот класс исключения один и тот же. Если у вашего EIBDataBaseError нет какого-нибудь IBErrorCode — то это криво спроектированные классы Interbase. Цитата Continental @ 27.10.09, 15:51 Так я не могу понять, как же мне отловить первую ошибку, или вторую вот с помощью такой конструкции: Если никакого поля с кодом нет, то по-хорошему — никак. (Т.е. вы можете, конечно, попробовать анализировать сообщение, но ведь его могут локализовать). Добавлено 27.10.09, 16:13
try IBDataBase.Connected:=true; except on E: EIBDataBaseError do if E.ErrorCode = XXX then begin sShowMessage(‘несуществующий путь бд!’); exit; end else if E.ErrorCode = YYY then begin sShowMessage(‘неверный пользователь или пароль’); exit; end else raise; end; Добавлено 27.10.09, 16:15
try IBDataBase.Connected:=true; except on E: Exception do begin if E is EIBDataBaseError then begin if EIBDataBaseError(E).ErrorCode = XXX then begin sShowMessage(‘несуществующий путь бд!’); exit; end else if EIBDataBaseError(E).ErrorCode = YYY then begin sShowMessage(‘неверный пользователь или пароль’); exit; end; end; ShowMessage(e.ClassName,E.Message+’ совершенно другая ошибка’); end; end; Добавлено 27.10.09, 16:17 |
|
mitrich |
|
|
Senior Member
Рейтинг (т): 99 |
Цитата CodeMonkey @ 27.10.09, 16:11 Если у вашего EIBDataBaseError нет какого-нибудь IBErrorCode
Именно так это свойство и называется, что нетрудно узнать из хелпа (который надеется на длительное и плодотворное сотрудничество с Continental |
|
Continental |
|
|
Senior Member
Рейтинг (т): 3 |
С облегчением …
try Connected:=true; except on E : EIBInterBaseError do begin sShowMessage(IntToStr(e.IBErrorCode),E.Message); exit; end; Спасибо всем, что открыли глаза. Добавлено 27.10.09, 17:01
except on E: Exception do begin if E is EIBDataBaseError then begin if EIBDataBaseError(E).ErrorCode = XXX then Я теперь это заделал в applicationevents. Теперь у меня будет и лог вестись и сообщения об ошибках выводится! Е-Е-Е! |
|
CodeMonkey |
|
|
Для лога ошибок имеет смысл использовать хук на исключения. См. JCL, EurekaLog, madExcept. Помимо сообщения этот способ позволит получить стек вызовов и состояние процессора в момент ошибки. С этой информацией зачастую продиагностировать ошибку можно даже не запуская отладчик. |
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:
- Предыдущая тема
- Delphi: Общие вопросы
- Следующая тема
[ Script execution time: 0,0466 ] [ 16 queries used ] [ Generated: 28.01.23, 21:30 GMT ]



