Raise — Ключевое слово Delphi

Raise — Ключевое слово Delphi

с помощью конструкции try .. exceprion можно экранировать ошибки, а как вывести сообщение об ошибке, скажем в Мемо?

Ну и ищи в хелпе по этим ключевым словам. Находится за секунды и с примером.

try
except On E:Exception
Memo1.Lines.Add (E.Message)
end

Че нить типа такого
try
.
except
on e:exception do
begin
MLog.Lines.Add(«Ошибка вышла «+#+e.Message);
raise Exception.Create(«Ошибка в разтаком-то модуле «+e.Message);
end;
end;

А On здесь зачем?


> А On здесь зачем?

Иначе undeclared identifier: «e»

> YurikGL © (14.06.08 19:40) [5]

Гы. и верно ведь. позор на мои седины. :o)


> Гы. и верно ведь. позор на мои седины. :o)

Вопрос, как к мастеру. насколько корректно
raise Exception.Create(«Ошибка в разтаком-то модуле «+e.Message);
в секции except?
Я использую эту конструкцию для «вытаскивания» всей цепочки ошибок. Т.е. если одна функция вызывает другую, та — третью и т.д. выйдет весь текст ошибки по цепочке.

> YurikGL © (14.06.08 20:49) [7]

Дык. а что ж тут некорректного? Все нормально.

Совет — посмотрите в сторону Assert, бывает очень полезно. Дело в том, что сообщение EAssertionFailed содержит имя модуля и номер строки. То есть, для локализации ошибки можно использовать что-то типа этого:
on E: Exception do
Assert(false, «Ошибка » + E.ClassName + «: » + E.Message);

можно и без on, через ExceptObject


> Юрий Зотов © (14.06.08 21:37) [8]

На E.ClassName ругается, зараза.


> Германн © (15.06.08 01:23) [10]
>
>
> > Юрий Зотов © (14.06.08 21:37) [8]
>
> На E.ClassName ругается, зараза.
>

Был не прав. Не ругается и не зараза.
:)

> Дык. а что ж тут некорректного? Все нормально.

Юрий, раньше Вы меня за такое ругали. А теперь это корректно? ;)

Сам обычно использую такую конструкцию:

function ReCreateEObject(E: Exception; const FuncName: string): Exception;
var
S: string;
begin
S := Format(«%s -> %s», [FuncName, E.Message]);
Result := ExceptClass(E.ClassType).Create(S);
end;

try
.
except
on E: Exception do
begin
.
raise ReCreateEObject(E, «MyFunc»);
end;
end;

> Loginov Dmitry © (15.06.08 10:45) [12]

1. За такое я ругать не мог (потому что это самый обычный способ «ручного» отслеживания и ругать тут не за что). А вот за что-то, хотя внешне и похожее, но по сути другое — мог.

2. Зачем пересоздавать объект исключения, если можно просто изменить его Message?


> Loginov Dmitry © (15.06.08 10:45) [12]

> Сам обычно использую такую конструкцию:

И сейчас будем ругать.
Хотя класс исключения будет тот же, но иная
дополнительная информация будет утеряна.

Сравни

try
raise TMyException.Create(«error»);
except
on E: TMyException do
begin
E.Message := Format(«reraise %s», [E.Message]);
raise;
end;
end;


Regards, LVT.

для системных исключений нельзая изменить текст. Изменение текста катит только для родных дельфийский эксепшенов.


> Loginov Dmitry © (15.06.08 17:42) [15]

> Изменение текста катит только для родных дельфийский эксепшенов.

В дельфи иных исключений и нет.

> В дельфи иных исключений и нет.

procedure TForm1.Button6Click(Sender: TObject);
var
a, b: double;
begin
a := 1;
b := 0;
try
a := a / b;
floattostr(a);
except
on E: Exception do
begin
E.Message := Format(«reraise %s», [E.Message]);
raise;
end;
end;
end;

Куда reraise девается? То-то же!


> Loginov Dmitry © (15.06.08 18:05) [17]

> Куда reraise девается? То-то же!

Ну и не надо никаких on E: Exception.
Если обработчику неизвестно исключение —
он _обязан_ его пропустить.

Raise — Ключевое слово Delphi

От Delphi 4 к Delphi 5.
Последовательность обработки исключений

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

Это можно представить следующим образом:

on EUnderflow do


on EOverflow do

on EZeroDivide do

on EMathError do

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

Теория, как известно, должна подкрепляться практикой. Рассмотрим пример с вложенными защищенными блоками.


procedure TForm1.Button1Click(Sender: TObject);

on EUnderflow do

MessageDlg (‘Потеря старших разрядов’,

on EZeroDivide do

MessageDlg (‘Произошло деление на нуль; повторите ввод’,

on EConvertError do

MessageDlg (‘Осуществите правильный ввод’,

Чтобы посмотреть работу, вложенных блоков защиты, произведите генерацию исключительной ситуации. Для этого введите нулевое значение в текстовый редактор Edit2 и любое числовое значение в текстовый редактор Edit1. При генерации данного исключения осуществляется поиск соответствующего ему обработчика on в том блоке try. except, в котором создалась исключительная ситуация. Для данного примера это секция on UnderFlow do. Если соответствующий обработчик не найден, поиск продолжается и производится в обрамляющем блоке try. except. Для нашего примера — это обработчик события деление на нуль числа с плавающей запятой, on EZeroDivide do, соответствует сгенерированной ситуации. Выдается сообщение, организованное вами в программном коде: » Произошло деление на нуль, повторите ввод».

Сгенерируйте другую исключительную ситуацию, введите буквенное значение в любой редактор текста Edit1, Edit2. Произведите деление, данная исключительная ситуация будет обработана на самом верхнем уровне, это секция try . except с обработчиком on EConvertError do (ошибка преобразования строк или объектов, в частности StrToFloat ) . Вы получите сообщение, созданное вами, «Осуществите правильный ввод». Как только оператор on, соответствующий данному исключению, найден и выполнен, объект исключения разрушается и управление передается оператору, следующему за тем блоком try. except, в котором осуществлен перехват.

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

Этот поиск продолжается по всем уровням. И только если он закончился безрезультатно, выполняется стандартная обработка исключения, заключающаяся в выдаче пользователю сообщения о типе исключения.

Для нашего случая произведите замену оператора on EConvertError do на on EmathError do, сгенерируйте исключительную ситуацию вводом буквенного выражения в текстовый редактор Edit1 — вы получите сообщение (рисунок 1) о необходимости ввода вещественного числа.


Преднамеренная генерация исключений, оператор raise.

В ряде случаев возникает необходимость сгенерировать исключительную ситуацию искусственно. Например, вы обработали какое-то исключение, но хотите, чтобы его обработка была завершена обработчиком внешнего по отношению к данному блоку try. except. Т.е. в этом случае необходимо сгенерировать повторно исключение того же типа, что и прежнее, ввиду того, что прежнее разрушено обработчиком исключения.

Повторная генерация исключительной ситуации осуществляется ключевым словом raise.

Delphi

КОМПЬЮТЕРНЫЕ КУРСЫ «ПОИСК»

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

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

С задачей перехвата ошибок и реагирования на них лучше всего справляется механизм обработки исключений (Структурированная обработка исключений (Structured exception handling – SHE) представляет собой метод обработки ошибок, благодаря которому можно восстановить нормальную работу приложения после сбоя в работе программы, который в противном случае был бы фатальным). Если в приложении, написанном с помощью Delphi, возникает ошибка, то приложение автоматически генерирует исключение. Исключением представляет собой объект, который описывает возникающую ошибку.

Генерация исключения означает всего лишь то, что приложение создало объект исключения и максимально подробно описало ошибку. Если мы не обрабатываем исключение (то есть не приготовлен специальный код для перехвата исключения), приложение само сделает это автоматически. Обычно приложение обрабатывает исключение, выводя на экран монитора окно с сообщением о возникшей ошибке. Например, если вы передадите функции StrToInt строку, содержащую пустую строку, то функция сгенерирует исключение.

Чтобы обработать исключение, сгенерированное функцией StrToInt, мы должны поместить вызов функции StrToInt в защищенный блок кода. Защищенным является блок кода, который может реагировать на некоторое исключение. В Delphi защищенный блок выглядит следующим образом:

try
оператор(ы)
except
операторы обработки исключения
end;

Операторы, которые могут сгенерировать исключение, записываются в блоке try, а в обработчике исключений пишется код, который занимается обработкой исключений. Обработчик исключения является частью защищенного блока, начинающегося с зарезервированного слова except в Delphi.

Если вы передадите функции StrToInt допустимую строку, и при этом исключение не возникнет, будет выполнен только тот код, который находится в блоке try. Код в блоке исключения выполняется только в том случае, если оператор, находящийся внутри этого блока, сгенерирует исключение.

Обработка специфических исключений в Delphi

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

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

Одно из них, EConvertError, может быть сгенерировано в том случае, если значение одного из компонентов TEdit невозможно преобразовать к целому типу, а другое, EDivByZero, может быть сгенерировано тогда, когда предпринимается попытка разделить первое число на 0.

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

on Некоторое-Исключение do Обработка_Исключения;

Конструкцию on-do можно использовать только в рамках обработчика исключений:

try
оператор (операторы);
except
on Исключение do Обработка_Исключения;
on Другое_Исключение do Его_Обработка;

По мере возможности, для обработки различных исключений лучше использовать конструкцию on-do. Например, вы можете обработать исключение EConvertError, выводя сообщение об ошибке, а исключение EDivByZero — уведомляя пользователя о том, что второе число не может быть равно нулю, и автоматически заменяя его единицей.

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

try
оператор (операторы);
except
on Исключение do Его_Обра6отка;
on Другое_Исключение do Его_Обработка;
else
Обработка_Всех_Остальных_Исключений;
end;

Зарезервированное слово raise используется для генерации исключения. Чтобы сгенерировать исключение в Delphi, используйте зарезервированное слово raise, указывая вслед за ним экземпляр объекта исключения. Экземпляром объекта исключения обычно является вызов конструктора исключения.

Синтаксис генерации исключения обычно выглядит следующим образом:

raise Класс_Исключения.Create(‘Сообщение_Об_Ошибке’);

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

Использование объекта исключения

Конструкция on-do позволяет получать на время объект исключения с помощью следующего синтаксиса

on Идентификатор: Исключение do Его_Обработка;

В качестве идентификатора обычно применяется заглавная буква Е. Когда вы получаете объект исключения, вы можете использовать его подобно любому другому объекту и даже обращаться к его свойствам и методам. Единственное, что не рекомендуется делать, это уничтожать объект исключения, поскольку объекты исключения автоматически управляются обработчиком исключения.

Создание специальных исключений в Delphi

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

type
EMyException = class(Exception);

В листинге ниже показана генерация и перехват специального исключения в Delphi.

Защита распределения ресурсов

Зарезервированное слово try позволяет построить два различных блока: блок обработчика, исключений и блок защиты ресурсов. Блок обработчика исключений создается с помощью зарезервированного слова except, а блок защиты ресурсов— с помощью зарезервированного слова finally. Синтаксическая структура блока защиты ресурсов в Delphi выглядит следующим образом:

try
.
finally
.
end;

Блоки обработки исключений и защиты ресурсов используются по-разному и работают также по-разному. Операторы обработчика исключений выполняются только в том случае, если операторы в блоке try сгенерировали исключение, а операторы в блоке finally выполняются всегда, даже если операторы в блоке try не сгенерировали никакого исключения. Если в блоке try возникнет исключение, управление будет передано блоку finally, после чего будет выполнен код очистки. Если в блоке try исключения не возникнут, операторы в блоке finally будут выполняться после операторов в блоке try.

Подходящим способом использования блока защиты ресурсов является распределение или, с другой стороны, затребование ресурса перед блоком try. После того как вы затребуете ресурс, поместите операторы, использующие ресурс, внутрь блока try. Когда работа с ресурсом будет завершена, вы должны будете освободить его. Операторы, освобождающие ресурс, должны быть написаны в блоке finally.

Блок защиты ресурса часто используется для того, чтобы обеспечить надлежащее освобождение динамически созданных объектов. Например, динамическое создание модальной формы необходимо всегда защищать с помощью блока try-finally.

В листинге ниже показан более короткий способ динамического создания формы, защищенной блоком try-finally.

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

Если вы хотите обработать исключение EDivByZero (или любое другое исключение) внутри блока защиты ресурсов, вы должны написать вложенный блок обработчика исключений.

Следующий листинг показывает, каким должен быть вложенный обработчик исключений внутри блока защиты ресурсов. Вы можете также вкладывать блоки защиты ресурсов в другие блоки защиты ресурсов или блоки обработки исключений.

ИЗМЕНЕНИЕ ОБРАБОТЧИКА ИСКЛЮЧЕНИЙ, ИСПОЛЬЗУЕМОГО ПО УМОЛЧАНИЮ

Глобальный объект Application отвечает за обработку исключений, не обрабатываемых блоком обработки исключений, который может находиться где-то в приложении. Чтобы изменить обработчик исключений, используемый по умолчанию, мы можем использовать компонент TApplicationEvents относящийся к категории Additional (Дополнительные).

Компонент TApplicationEvents предлагает событие OnException, которое генерируется всякий раз, когда возникает необработанное исключение.

Событие OnException может быть обработано с помощью процедуры типа TExceptionEvent. Процедура, обрабатывающая событие OnException, принимает два параметра: объект Sender и объект Exception.

procedure TMainForm.AppEventsException[Sender: TObject; E: Exception);
begin

В рамках обработчика события OnException вы можете написать код, который будет обрабатывать исключения иным способом, нежели обработчик, используемый по умолчанию, или же оставить обработчик события пустым. Если вы не хотите, чтобы при возникновении исключения что-либо происходило, оставьте обработчик события пустым. В данном случае потребуется написать внутри блока обработчика события только какой-нибудь комментарий, чтобы редактор Code Editor не удалил код обработчика автоматически.

Илон Маск рекомендует:  Что такое код odbc_setoption

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

В листинге ниже показано, как производится регистрация исключений внутри обработчика события OnException.

Вы можете также модифицировать обработчик исключений, используемый по умолчанию, вручную (без применения компонента TApplicationEvents). Для этого нужно создать метод, который будет принимать те же параметры, что и событие OnException и назначить этот метод событию OnException в глобальном объекте Application.

Источник: Иван Хладни — Внутренний мир Borland Delphi 2006.

Exceptions (Delphi)

This topic covers the following material:

  • A conceptual overview of exceptions and exception handling
  • Declaring exception types
  • Raising and handling exceptions

Contents

About Exceptions

An exception is raised when an error or other event interrupts normal execution of a program. The exception transfers control to an exception handler, which allows you to separate normal program logic from error-handling. Because exceptions are objects, they can be grouped into hierarchies using inheritance, and new exceptions can be introduced without affecting existing code. An exception can carry information, such as an error message, from the point where it is raised to the point where it is handled.

When an application uses the SysUtils unit, most runtime errors are automatically converted into exceptions. Many errors that would otherwise terminate an application — such as insufficient memory, division by zero, and general protection faults — can be caught and handled.

When To Use Exceptions

Exceptions prov >try. except or try. finally statement, in practice these tools are best reserved for special situations.

Exception handling is appropriate for errors whose chances of occurring are low or difficult to assess, but whose consequences are likely to be catastrophic (such as crashing the application); for error conditions that are complicated or difficult to test for in if. then statements; and when you need to respond to exceptions raised by the operating system or by routines whose source code you don’t control. Exceptions are commonly used for hardware, memory, I/O, and operating-system errors.

Conditional statements are often the best way to test for errors. For example, suppose you want to make sure that a file exists before trying to open it. You could do it this way:

But you could also avoid the overhead of exception handling by using:

Assertions prov >Assert statement fails, the program either halts with a runtime error or (if it uses the SysUtils unit) raises an SysUtils.EAssertionFailed exception. Assertions should be used only to test for conditions that you do not expect to occur.

Declaring Exception Types

Exception types are declared just like other >SysUtils .

You can group exceptions into families using inheritance. For example, the following declarations in SysUtils define a family of exception types for math errors:

Given these declarations, you can define a single SysUtils.EMathError exception handler that also handles SysUtils.EInvalidOp, SysUtils.EZeroDivide, SysUtils.Overflow, and SysUtils.EUnderflow.

Exception classes sometimes define fields, methods, or properties that convey additional information about the error. For example:

Raising and Handling Exceptions

To raise an exception object, use an instance of the exception class with a raise statement. For example:

In general, the form of a raise statement is

where object and at address are both optional. When an address is specified, it can be any expression that evaluates to a pointer type, but is usually a pointer to a procedure or function. For example:

Use this option to raise the exception from an earlier point in the stack than the one where the error actually occurred.

When an exception is raised — that is, referenced in a raise statement — it is governed by special exception-handling logic. A raise statement never returns control in the normal way. Instead, it transfers control to the innermost exception handler that can handle exceptions of the given >try. except block was most recently entered but has not yet exited.)

For example, the function below converts a string to an integer, raising an SysUtils.ERangeError exception if the resulting value is outside a specified range.

Notice the CreateFmt method called in the raise statement. SysUtils.Exception and its descendants have special constructors that provide alternative ways to create exception messages and context IDs.

A raised exception is destroyed automatically after it is handled. Never attempt to destroy a raised exception manually.

Note: Raising an exception in the initialization section of a unit may not produce the intended result. Normal exception support comes from the SysUtils unit, which must be initialized before such support is available. If an exception occurs during initialization, all initialized units — including SysUtils — are finalized and the exception is re-raised. Then the exception is caught and handled, usually by interrupting the program. Similarly, raising an exception in the finalization section of a unit may not lead to the intended result if SysUtils has already been finalized when the exception has been raised.

Try. except Statements

Exceptions are handled within try. except statements. For example:

This statement attempts to div >Y by Z , but calls a routine named HandleZeroDivide if an SysUtils.EZeroDivide exception is raised.

The syntax of a try. except statement is:

where statements is a sequence of statements (delimited by semicolons) and exceptionBlock is either:

  • another sequence of statements or
  • a sequence of exception handlers, optionally followed by

An exception handler has the form:

where identifier: is optional (if included, identifier can be any valid identifier), type is a type used to represent exceptions, and statement is any statement.

A try. except statement executes the statements in the initial statements list. If no exceptions are raised, the exception block (exceptionBlock) is ignored and control passes to the next part of the program.

If an exception is raised during execution of the initial statements list, either by a raise statement in the statements list or by a procedure or function called from the statements list, an attempt is made to ‘handle’ the exception:

  • If any of the handlers in the exception block matches the exception, control passes to the first such handler. An exception handler ‘matches’ an exception just in case the type in the handler is the class of the exception or an ancestor of that class.
  • If no such handler is found, control passes to the statement in the else clause, if there is one.
  • If the exception block is just a sequence of statements without any exception handlers, control passes to the first statement in the list.

If none of the conditions above is satisfied, the search continues in the exception block of the next-most-recently entered try. except statement that has not yet exited. If no appropriate handler, else clause, or statement list is found there, the search propagates to the next-most-recently entered try. except statement, and so forth. If the outermost try. except statement is reached and the exception is still not handled, the program terminates.

When an exception is handled, the stack is traced back to the procedure or function containing the try. except statement where the handling occurs, and control is transferred to the executed exception handler, else clause, or statement list. This process discards all procedure and function calls that occurred after entering the try. except statement where the exception is handled. The exception object is then automatically destroyed through a call to its Destroy destructor and control is passed to the statement following the try. except statement. (If a call to the Exit , Break , or Continue standard procedure causes control to leave the exception handler, the exception object is still automatically destroyed.)

In the example below, the first exception handler handles division-by-zero exceptions, the second one handles overflow exceptions, and the final one handles all other math exceptions. SysUtils.EMathError appears last in the exception block because it is the ancestor of the other two exception classes; if it appeared first, the other two handlers would never be invoked:

An exception handler can specify an >on. do . The scope of the identifier is limited to that statement. For example:

If the exception block specifies an else clause, the else clause handles any exceptions that aren’t handled by the block’s exception handlers. For example:

Here, the else clause handles any exception that isn’t an SysUtils.EMathError.

An exception block that contains no exception handlers, but instead consists only of a list of statements, handles all exceptions. For example:

Here, the HandleException routine handles any exception that occurs as a result of executing the statements between try and except.

Re-raising Exceptions

When the reserved word raise occurs in an exception block without an object reference following it, it raises whatever exception is handled by the block. This allows an exception handler to respond to an error in a limited way and then re-raise the exception. Re-raising is useful when a procedure or function has to clean up after an exception occurs but cannot fully handle the exception.

For example, the GetFileList function allocates a TStringList object and fills it with file names matching a specified search path:

GetFileList creates a TStringList object, then uses the FindFirst and FindNext functions (defined in SysUtils ) to initialize it. If the initialization fails — for example because the search path is inval >GetFileList needs to dispose of the new string list, since the caller does not yet know of its existence. For this reason, initialization of the string list is performed in a try. except statement. If an exception occurs, the statement’s exception block disposes of the string list, then re-raises the exception.

Nested Exceptions

Code executed in an exception handler can itself raise and handle exceptions. As long as these exceptions are also handled within the exception handler, they do not affect the original exception. However, once an exception raised in an exception handler propagates beyond that handler, the original exception is lost. This is illustrated by the Tan function below:

If an SysUtils.EMathError exception occurs during execution of Tan, the exception handler raises an ETrigError . Since Tan does not prov >ETrigError , the exception propagates beyond the original exception handler, causing the SysUtils.EMathError exception to be destroyed. To the caller, it appears as if the Tan function has raised an ETrigError exception.

Try. finally Statements

Sometimes you want to ensure that specific parts of an operation are completed, whether or not the operation is interrupted by an exception. For example, when a routine acquires control of a resource, it is often important that the resource be released, regardless of whether the routine terminates normally. In these situations, you can use a try. finally statement.

The following example shows how code that opens and processes a file can ensure that the file is ultimately closed, even if an error occurs during execution:

The syntax of a try. finally statement is

where each statementList is a sequence of statements delimited by semicolons. The try. finally statement executes the statements in statementList1 (the try clause). If statementList1 finishes without raising exceptions, statementList2 (the finally clause) is executed. If an exception is raised during execution of statementList1, control is transferred to statementList2; once statementList2 finishes executing, the exception is re-raised. If a call to the Exit , Break , or Continue procedure causes control to leave statementList1, statementList2 is automatically executed. Thus the finally clause is always executed, regardless of how the try clause terminates.

If an exception is raised but not handled in the finally clause, that exception is propagated out of the try. finally statement, and any exception already raised in the try clause is lost. The finally clause should therefore handle all locally raised exceptions, so as not to disturb propagation of other exceptions.

Заметки о Pascal, Delphi и Lazarus

Следует ожидать переводов разделов справочной системы Delphi, компиляций из учебников, переводы статей, «путевые заметки» и прочие интересности. Блог прежде всего ориентирован на студентов, но опытных людей я тоже буду рад видеть;-)

суббота, 19 мая 2012 г.

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

Перевод раздела Exceptions из справочной системы Delphi

Об исключениях

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

Когда приложение подключает модуль SysUtils большая часть ошибок, возникающих при выполнении программы, автоматически преобразуется в исключения. Значительная часть ошибок, результатом которых могло бы стать завершение программы (такие как недостаток памяти, деление на ноль, ошибки общей защиты) перехватываются и обрабатываются.

Когда следует применять исключения

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

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

  • трудноопределимых ошибок, вероятность возникновения которых невелика, но последствия которых могут оказаться серьезными (например, аварийное завершение приложения);
  • ошибок, возникновение которых трудно отследить при помощи инструкций if. then ;
  • случаев, когда необходимо реагировать на исключительные ситуации, создаваемые операционной системой или другими программами, код которых вы не контролируете.

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

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

Но для экономии ресурсов можно использовать и другой способ:

Утверждения (Assertions) дают еще одну возможность проверки логических условий в вашем исходном коде. Если при выполнении инструкции Assert происходит ошибка, приложение либо завершается, либо (в том случае, если подключен модуль SysUtils) создает исключение SysUtils.EAssertionFailed. Утверждения должны использоваться только для проверки условий, невыполнения которых вы не ожидаете.

Объявление типов исключений

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

Вы можете объединять исключения в семейства при помощи наследования. Приведенные ниже объявления из модуля SysUtils объявляют семейство исключений для обработки математических ошибок:

Сделав такие объявления, вы можете создать один обработчик исключений для SysUtils.EMathError, который сможет работать с SysUtils.EInvalidOp, SysUtils.EZeroDivide, SysUtils.Overflow и SysUtils.EUnderflow.

Классы исключений иногда содержат поля, методы или свойства для передачи дополнительной информации об ошибке:

Инициирование и обработка исключений

Для инициирования исключения вам необходимо использовать экземпляр класса исключения с инструкцией raise:

Илон Маск рекомендует:  Свойство margin

Вообще говоря, инструкция инициирования исключения имеет следующий вид:

где object и at address являются опциональными. Когда указывается address, им может быть любое выражение, которое можно обработать как указатель. Обычно это указатель на процедуру или функцию. Например:

Этой опцией можно инициировать исключение из участка стека, предшествующего тому, в котором на самом деле случилась ошибка. Когда исключение инициировано, то есть после вызова инструкции raise, управление им осуществляется по специальному принципу обработки исключительных ситуаций. Инструкция raise не возвращает управление в точку своего выполнения. Вместо этого управление передается обработчику исключений соответствующего класса, который находится в самом большом уровне вложенности блоков try except (т.е. относящийся к блоку, вход в который был осуществлен позже всего).

Например, приведенная ниже функция преобразует строку в целое число и инициирует исключение в том случае, если результирующее значение не находится в обозначенном диапазоне.

Обратите внимание на метод CreateFmt , вызываемый в инструкции raise. Класс SysUtils.Exception и его потомки оснащены особыми конструкторами, которые предоставляют возможность создавать сообщения об ошибках и идентификаторы контекста.

Инициированное исключение автоматически разрушается после его обработки. Не следует пытаться разрушать исключения самостоятельно.

Замечание: Вызов (инициирование) исключения в секции инициализации модуля может не привести к ожидаемому результату. Обычно обработка исключительных ситуаций выполняется из модуля SysUtils, который должен быть инициализирован прежде чем выполнять такие функции. Если исключительная ситуация имеет место в процессе инициализации – все инициализированные модули (включая SysUtils) финализируются, а исключение инициируется повторно. Затем, после перехвата, исключение обрабатывается (обычно завершением приложения). Инициирование исключений в секции финализации модуля также может не привести к нужному результату, в том случае, если на момент инициирования исключения модуль SysUtils уже финализирован.

Инструкции Try. except

Исключительные ситуации обрабатываются обрабатываются внутри конструкций try. except. Например:

Эта конструкция предпринимает попытку деления y на z, а в случае возникновения исключительной ситуации SysUtils.EZeroDivide вызывает подпрограмму HandleZeroDivide.

Синтаксис инструкции try. except:

где statements – это последовательность инструкций, разделенных точками с запятой (;), а exceptionBlock – может быть:

  • еще одной последовательностью инструкций
  • еще одной последовательностью инструкций или последовательностью обработчиков исключений, разделяемых инструкциями else.

Обработчик исключения имеет вид:

где identifier: необязателен (если присутствует – может быть любым допустимым идентификатором), type – это тип для представления исключений, а statement – это любая инструкция.

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

Если в процессе выполнения списка команд возникла исключительная ситуация (она может быть инициирована инструкцией raise в списке команд или внутри процедуры или функции, вызываемой из этого списка) предпринимается попытка обработки исключительной ситуации:

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

Если обработчика не найдено, управление передается инструкции в секции else (если таковая присутствует).

Если блок обработчиков – это просто последовательность инструкций без каких либо обработчиков – управление передается первой инструкции в этой последовательности.

Если ни одно из указанных выше условий не выполнено, поиск продолжается в блоке обработчиков внешней инструкции try. except , выход из которой еще не выполнен. Если и там не находится соответствующего обработчика, секции else или последовательности инструкций, поиск продолжается в следующей внешней инструкции и так далее. Если в самой внешней инструкции исключительная ситуация не будет обработана – приложение завершается.

Когда исключительная ситуация обработана, в стеке находится процедура или функция, содержащая инструкцию try. except , в которой произошла обработка и управление передается выполненному обработчику, секции else или последовательности инструкций. Этот процесс отменяет все вызовы процедур и функций, имевшие место после входа в блок try. except, в котором исключительная ситуация была обработана. Объект исключения автоматически разрушается вызовом деструктора Destroy и упрвление передается инструкции, следующей за блоком try. except. (Если вызов стандартных процедур Exit, Break или Continue выводит управление из обработчика, объект исключения также разрушается).

В следующем примере первый обработчик обрабатывает исключение деления на ноль, второй – ошибки переполнения, а последний – остальные математические исключения. SysUtils.EMathError указан последним в блоке обработчиков, так как он является предком обоих этих классов. Если бы он указан первым, последующие обработчики никогда не были бы вызваны:

В обработчике исключения перед именем класса исключения можно указать идентификатор. Таким образом объявляется идентификатор для представления объекта исключения в процессе выполнения инструкции, следующей за on. do. Видимость идентификатора ограничивается этой инструкцией. Например:

Если блок исключения имеет секцию else, в этой секции происходит обработка всех исключений, которые не были обработаны в блоке обработчика исключения. То есть:

В этом примере секция else обрабатывает все исключения, не являющимися SysUtils.EMathError.

Блок исключения, не содержащий обработчиков, но содержащий список инструкций, обрабатывает любые исключения. Например:

Здесь подпрограмма HandleException обрабатывает все исключенительные ситуации, которые возникают при выполнении инструкций между try и except.

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

Когда ключевое слово raise включается в блок исключения без указания ссылки на объект, оно инициирует исключение, уже обработанное в блоке. Это позволяет обработчику исключения среагировать на ошибку и затем повторно инициировать исключение. Повторное инициирование исключения может оказаться полезным, когда процедура или функция должна освободить память после своего выполнения, но не может полностью обработать исключение.

Например, функция GetFileList создает объект TStringList и заполняет его именами файлов, расположенными в определенной для поиска папке:

GetFileList создает объект TStringList, затем применяет функции FindFirst и FindNext (определены в модуле SysUtils) для его инициализации. Если в процессе инициализации происходит ошибка – например, из-за того, что путь задан неверно или для заполенения списка строк недостаточно памяти — GetFileList нужно высвободить память созданного списка при том, что вызывающая подпрограмма ничего не знает о его существовании. По этой причине, инициализация списка строк выполняется внутри инструкции try. except. Если возникает исключительная ситуация, блок обработки исключения разрушает список строк и повторно инициирует исключение.

Встроенные исключения

Код, выполняемый в обработчике исключения может сам инициировать и обрабатывать исключительные ситуации. Поскольку исключения обрабатываются внутри обработчика, они не оказывают влияния на первичное исключение. Тем не менее, если исключение инициированное внутри обработчика, не обрабатывается в нем, первичное исключение теряется. Эту ситуацию иллюстрирует функция Tan, код которой приведен ниже:

Если исключение SysUtils.EMathError инициируется при выполнении Tan, обработчик инициирует исключение ETrigError. Поскольку Tan не имеет обработчика для ETrigError, это исключение выходит из обработчика, тем самым вызывая разрушение исключения SysUtils.EMathError. Вызывающей подпрограмме передается ETrigErrorexception, инициированное внутри функции Tan.

Инструкции Try. finally

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

В следующем примере показан код, который открывает и обрабатывает файл, при этом файл будет в конечном итоге закрыт, даже если в процессе обработки произойдет ошибка:

Синтаксис инструкции try. finally выглядит следующим образом:

где каждый statementList – это последовательность инструкций, разделенных точками с запятой (;). Инструкция try. finally выполняет инструкции в statementList1 (секция try). Если выполнение statementList1 завершается без ошибок, выполняется statementList2 (секция finally). Если в процессе выполнения statementList1 возникает исключительная ситуация, управление передается в statementList2, когда statementList2 завершает свою работу исключение инициируется повторно. Если в процессе выполнения statementList1 происходит вызов процедур Exit, Break или Continue – управление выходит из statementList1 , statementList2 выполняется автоматически. Таким образом секция finally выполняется всегда, вне зависимости от того, как завершается работа секции try.

Если в секции finally возникает исключительная ситуация, которая не обрабатывается, исключение выводится из из инструкции try. finally, а исключение, инициированное в секции try, разрушается. Таким образом, секция finally должна обработать все внутренние исключительные ситуации с тем, чтобы они не были переданы за пределы секции.

How to raise exceptions in Delphi?

I’m asking for Delphi native,not Prism(net).

This is my code:

Undeclarated idenitifier «Exception».

Where’s the problem,how do I throw/raise exceptions?

4 Answers 4

The exception class «Exception» is declared in the unit SysUtils. So you must add «SysUtils» to your uses-clause.

Remember to add SYSUTILS to your uses units.

I also suggest you a nice way to keep track of categories, formats of messagges and meaning of exception:

A simple way of using this is:

You may need to add sysutils to the uses clause, it is not built in and is optional according to Delphi in a nutshell.

You are using SysUtils aren’t you? Exception is declared in there IIRC.

Not the answer you’re looking for? Browse other questions tagged delphi exception or ask your own question.

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2020.11.11.35402

DelphiComponent.ru — бесплатно видеоуроки по Delphi, статьи, исходники

Обработка исключений в Delphi

Разрабатывая какое-нибудь приложение, вы должны написать код. который будет решать поставленную задачу, а также код, который будет выполнять проверку на наличие ошибок. Как правило, код для обработки ошибок строится на основе оператора if.

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

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

Генерация исключения означает всего лишь то. что приложение создало объект исключения и максимально подробно описало ошибку.

Если мы не обрабатываем исключение (то есть не приготовлен специальный код для перехвата исключения), приложение само сделает это автоматически. Обычно приложение обрабатывает исключение, выводя на экран монитора окно с сообщением о возникшей ошибке. Например, если вы передадите функции StrToInt строку, содержащую символы, которые не могут быть преобразованы в числовое значение, или вообще пустую строку, то функция сгенерирует исключение (рис. 13.1).

Рис. 13.1. Исключение, обработанное приложением

Чтобы обработать исключение, сгенерированное функцией StrToInt, мы должны поместить вызов функции StrToInt в защищенный блок кода. Защищенным является блок кода, который может реагировать на некоторое исключение. В Delphiзащищенный блок выглядит следующим образом:

Raise — Ключевое слово Delphi

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

Модель исключительных ситуаций в Delphi

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

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

Вызов исключительной ситуации

Доступ к экземпляру объекта exception

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

Исключения, возникающие при работе с базами данных

    1. Обзор
    2. С целью поддержки структурной обработки исключительных ситуаций ( exception ) в Delphi введены новые расширения языка Pascal. В данной статье будет дано описание того, что из себя представляет такая обработка, почему она полезна, будут приведены соответствующий синтаксис Object Pascal и примеры использования исключительных ситуаций в D elphi.
    3. Структурная обработка исключительных ситуаций
    4. Структурная обработка исключительных ситуаций — это система, позволяющая программисту при возникновении ошибки (исключительной ситуации) связаться с кодом программы, подготовленным для обработки такой ошибки. Это выполняется с помощью языковых конструкций, которые как бы “охраняют” фрагмент кода программы и определяют обработчики ошибок, которые будут вызываться, если что-то пойдет не так в “охраняемом” участке кода. В данном случае понятие исключительной ситуации относится к языку и не нужно его путать с системными исключительными ситуациями (hardware exceptions), такими как General Protection Fault. Эти исключительные ситуации обычно используют прерывания и особые состояния “железа” для обработки критичной системной ошибки; исключительные ситуации в Delphi же независимы от “железа”, не используют прерываний и используются для обработки ошибочных состояний, с которыми подпрограмма не готова иметь дело. Системные исключительные ситуации, конечно, могут быть перехвачены и преобразованы в языковые исключительные ситуации, но это только одно из применений языковых исключительных ситуаций.

    При традиционной обработке ошибок, ошибки, обнаруженные в процедуре обычно передаются наружу (в вызывавшую процедуру) в виде возвращаемого значения функции, параметров или глобальных переменных (флажков). Каждая вызывающая процедура должна проверять результат вызова на наличие ошибки и выполнять соответствующие действия. Часто, это просто выход еще выше, в более верхнюю вызывающую процедуру и т.д. : функция A вызывает B, B вызывает C, C обнаруживает ошибку и возвращает код ошибки в B, B проверяет возвращаемый код, видит, что возникла ошибка и возвращает код ошибки в A, A проверяет возвращаемый код и выдает сообщение об ошибке либо решает сделать что-нибудь еще, раз первая попытка не удалась.

    Такая “пожарная бригада” для обработки ошибок трудоемка, требует написания большого количества кода в котором можно легко ошибиться и который трудно отлаживать.

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

    Структурная обработка исключительной ситуации замещает ручную обработку ошибок автоматической, сгенерированной компилятором системой уведомления. В приведенном выше примере, процедура A установила бы “охрану” со связанным обработчиком ошибки на фрагмент кода, в котором вызывается B. B просто вызывает C. Когда C обнаруживает ошибку, то создает ( raise ) исключительную ситуацию. Специальный код, сгенерированный компилятором и встроенный в Run-Time Library (RTL) начинает поиск обработчика данной исключительной ситуации. При поиске “защищенного” участка кода используется информация, сохраненная в стеке. В процедурах C и B нет такого участка, а в A — есть. Если один из обработчиков ошибок, которые используются в A, подходит по типу для возникшей в C исключительной ситуации, то программа переходит на его выполнение. При этом, область стека, используемая в B и C, очищается; выполнение этих процедур прекращается.

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

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

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

  1. Модель исключительных ситуаций в Delphi
  2. Модель исключительных ситуаций в Object Pascal является невозобновляемой( non-resumable ). При возникновении исключительной ситуации Вы уже не сможете вернуться в точку, где она возникла, для продолжения выполнения программы (это позволяет сделать возобновляемая( resumable ) модель). Невозобновляемые исключительные ситуации разрушают стек, поскольку они сканируют его в поисках обработчика; в возобновляемой модели необходимо сохранять стек, состояние регистров процессора в точке возникновения ошибки и выполнять поиск обработчика и его выполнение в отдельном стеке. Возобновляемую систему обработки исключительных ситуаций гораздо труднее создать и применять, нежели невозобновляемую.
  3. Синтаксис обработки исключительных ситуаций
Илон Маск рекомендует:  Лекции по конструированию компиляторов литература

Теперь, когда мы рассмотрели, что такое исключительные ситуации, давайте дадим ясную картину, как они применяются. Новое ключевое слово, добавленное в язык Object Pascal — try . Оно используется для обозначения первой части защищенного участка кода. Существует два типа защищенных участков:

Первый тип используется для обработки исключительных ситуаций. Его синтаксис:

on Exception1 do Statement;

on Exception2 do Statement;

Для уверенности в том, что ресурсы, занятые вашим приложением, освободятся в любом случае, Вы можете использовать конструкцию второго типа. Код, расположенный в части finally, выполняется в любом случае, даже если возникает исключительная ситуация. Соответствующий синтаксис:

      1. Примеры обработки исключительных ситуаций
      2. Ниже приведены процедуры A,B и C, обсуждавшиеся ранее, воплощенные в новом синтаксисе Object Pascal:

      if (ErrorCondition) then

      writeln(‘Raising exception in C’);

      writeln(‘Enter A»s try block’);

      writeln(‘After B call’);

      on ESampleError do

      writeln(‘Inside A»s ESampleError handler’);

      on ESomethingElse do

      writeln(‘Inside A»s ESomethingElse handler’);

      При ErrorCondition = True программа выдаст:

      Enter A’s try block

      Raising exception in C

      Inside A’s ESampleError handler

      Возможно вас удивила декларация типа ‘ESampleError = . Описание новой объектной модели дается в других уроках. Здесь же достаточно сказать, что исключительные ситуации (exceptions) являются классами, частью новой объектной модели.

      Процедура C проверяет наличие ошибки (в нашем случае это значение глобальной переменной) и, если она есть (а это так), C вызывает(raise) исключительную ситуацию класса ESampleError.

      Процедура A помещает часть кода в блок try..except. Первая часть этого блока содержит часть кода, аналогично конструкции begin..end . Эта часть кода завершается ключевым словом except , далее следует один или более обработчиков исключительных ситуаций on xxxx do yyyy , далее может быть включен необязательный блок else, вся конструкция заканчивается end; . В конструкции, назначающей определенную обработку для конкретной исключительной ситуации ( on xxxx do yyyy ), после резервного слова on указывается класс исключительной ситуации, а после do следует собственно код обработки данной ошибки. Если возникшая исключительная ситуация подходит по типу к указанному после on , то выполнение программы переходит сюда (на код после do ). Исключительная ситуация подходит в том случае, если она того же класса, что указан в on, либо является его потомком. Например, в случае on EFileNotFound обрабатываться будет ситуация, когда файл не найден. А в случае on EFileIO — все ошибки при работе с файлами, в том числе и предыдущая ситуация. В блоке else обрабатываются все ошибки, не обработанные до этого.

      Приведенные в примере процедуры содержат код (строка с writeln), который отображает путь выполнения программы. Когда C вызывает exception, программа сразу переходит на обработчик ошибок в процедуре A, игнорируя оставшуюся часть кода в процедурах B и C.

      После того, как найден подходящий обработчик ошибки, поиск оканчивается. После выполнения кода обработчика, программа продолжает выполняться с оператора, стоящего после слова end блока try..except (в примере — writeln(‘Exit A’)).

      Конструкция try..except подходит, если известно, какой тип ошибок нужно обрабатывать в конкретной ситуации. Но что делать, если требуется выполнить некоторые действия в любом случае, произошла ошибка или нет? Это тот случай, когда понадобится конструкция try..finally.

      Рассмотрим модифицированную процедуру B:

      Если C вызывает исключительную ситуацию, то программа уже не возвращается в процедуру B. А что же с теми 1000 байтами памяти, захваченными в B? Строка FreeMem(P,1000) не выполнится и Вы потеряете кусок памяти. Как это исправить? Нужно ненавязчиво включить процедуру B в процесс, например:

      writeln(‘enter NewB»s try block’);

      writeln(‘end of NewB»s try block’);

      writeln(‘inside NewB»s finally block’);

      Если в A поместить вызов NewB вместо B, то программа выведет сообщения следующим образом:

      Enter A’s try block

      enter NewB’s try block

      Raising exception in C

      inside NewB’s finally block

      Inside A’s ESampleError handler

      Код в блоке finally выполнится при любой ошибке, возникшей в соответствующем блоке try . Он же выполнится и в том случае, если ошибки не возникло. В любом случае память будет освобождена. Если возникла ошибка, то сначала выполняется блок finally, затем начинается поиск подходящего обработчика. В штатной ситуации, после блока finally программа переходит на следующее предложение после блока.

      Почему вызов GetMem не помещен внутрь блока try ? Этот вызов может окончиться неудачно и вызвать exception EOutOfMemory. Если это произошло, то FreeMem попытается освободить память, которая не была распределена. Когда мы размещаем GetMem вне защищаемого участка, то предполагаем, что B сможет получить нужное количество памяти, а если нет, то более верхняя процедура получит уведомление EOutOfMemory.

      А что, если требуется в B распределить 4 области памяти по схеме все-или-ничего? Если первые две попытки удались, а третья провалилась, то как освободить захваченную область память? Можно так:

      writeln(‘enter B»s try block’);

      writeln(‘end of B»s try block’);

      writeln(‘inside B»s finally block’);

      if P <> nil then FreeMem(P, 1000);

      if Q <> nil then FreeMem(Q, 1000);

      if R <> nil then FreeMem(R, 1000);

      if S <> nil then FreeMem(S, 1000);

      Установив сперва указатели в NIL, далее можно определить, успешно ли прошел вызов GetMem.

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

    1. Вызов исключительной ситуации
    2. В процедуре C из примера мы уже могли видеть, как должна поступать программа при обнаружении состояния ошибки — она вызывает исключительную ситуацию:

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

      Почти все существующие классы исключительных ситуаций являются наследниками базового класса Exception и не содержат новых свойств или методов. Класс Exception имеет несколько конструкторов, какой из них конкретно использовать — зависит от задачи. Описание класса Exception можно найти в on-line Help.

    3. Доступ к экземпляру объекта exception
    4. До сих пор мы рассматривали механизмы защиты кода и ресурсов, логику работы программы в исключительной ситуации. Теперь нужно немного разобраться с тем, как же обрабатывать возникшую ошибку. А точнее, как получить дополнительную информацию о коде ошибки, текст сообщения и т.п.

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

      Рассмотрим модифицированную процедуру A в нашем примере:

      writeln(‘Enter A»s try block’);

      writeln(‘After B call’);

      on E: ESampleError do writeln(E.Message);

      on ESomethingElse do

      writeln(‘Inside A»s ESomethingElse handler’);

      Здесь все изменения внесены в строку

      on ESE: ESampleError do writeln(ESE.Message);

      Пример демонстрирует еще одно новшество в языке Object Pascal — создание локальной переменной. В нашем примере локальной переменной является ESE — это тот самый экземпляр класса ESampleError, который был создан в процедуре C в момент вызова исключительного состояния. Переменная ESE доступна только внутри блока do. Свойство Message объекта ESE содержит сообщение, которое было передано в конструктор Create в процедуре C.

      Есть еще один способ доступа к экземпляру exception — использовать функцию ExceptionObject:

      on ESampleError do

      writeln( ESample Error(ExceptionObject).Message);

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

      • Exception — базовый класс-предок всех обработчиков исключительных ситуаций.
      • EAbort — “ скрытое” исключение. Используйте его тогда, когда хотите прервать тот или иной процесс с условием, что пользователь программы не должен видеть сообщения об ошибке. Для повышения удобства использования в модуле SysUtils предусмотрена процедура Abort , определенная, как:

      raise EAbort.CreateRes(SOperationAborted) at ReturnAddr;

      • EComponentError — вызывается в двух ситуациях:
    5. 1) при попытке регистрации компоненты за пределами процедуры Register;

      2) когда имя компоненты не уникально или не допустимо.

      • EConvertError — происходит в случае возникновения ошибки при выполнении функций StrToInt и StrToFloat , когда конвертация строки в соответствующий числовой тип невозможна.
      • EInOutError — происходит при ошибках ввода/вывода при включенной директиве <$I+>.
      • EIntError — предок исключений, случающихся при выполнении целочисленных операций.
      • EDivByZero — вызывается в случае деления на ноль, как результат RunTime Error 200.
      • EIntOverflow — вызывается при попытке выполнения операций, приводящих к переполнению целых переменных, как результат RunTime Error 215 при включенной директиве <$Q+>.
      • ERangeError — вызывается при попытке обращения к элементам массива по индексу, выходящему за пределы массива, как результат RunTime Error 201 при включенной директиве <$R+>.
      • EInvalidCast — происходит при попытке приведения переменных одного класса к другому классу, несовместимому с первым (например, приведение переменной типа TListBox к TMemo).
      • EInvalidGraphic — вызывается при попытке передачи в LoadFromFile файла, несовместимого графического формата.
      • EInvalidGraphicOperation — вызывается при попытке выполнения операций, неприменимых для данного графического формата (например, Resize для TIcon).
      • EInvalidObject — реально нигде не используется, объявлен в Controls.pas.
      • EInvalidOperation — вызывается при попытке отображения или обращения по Windows-обработчику (handle) контрольного элемента, не имеющего владельца (например, сразу после вызова MyControl:=TListBox.Create(. ) происходит обращение к методу Refre sh).
      • EInvalidPointer — происходит при попытке освобождения уже освобожденного или еще неинициализированного указателя, при вызове Dispose(), FreeMem() или деструктора класса.
      • EListError — вызывается при обращении к элементу наследника TList по индексу, выходящему за пределы допустимых значений (например, объект TStringList содержит только 10 строк, а происходит обращение к одиннадцатому).
      • EMathError — предок исключений, случающихся при выполнении операций с плавающей точкой.
      • EInvalidOp — происходит, когда математическому сопроцессору передается ошибочная инструкция. Такое исключение не будет до конца обработано, пока Вы контролируете сопроцессор напрямую из ассемблерного кода.
      • EOverflow — происходит как результат переполнения операций с плавающей точкой при слишком больших величинах. Соответствует RunTime Error 205.
      • Underflow — происходит как результат переполнения операций с плавающей точкой при слишком малых величинах. Соответствует RunTime Error 206.
      • EZeroDivide — вызывается в результате деления на ноль.
      • EMenuError — вызывается в случае любых ошибок при работе с пунктами меню для компонент TMenu, TMenuItem, TPopupMenu и их наследников.
      • EOutlineError — вызывается в случае любых ошибок при работе с TOutLine и любыми его наследниками.
      • EOutOfMemory — происходит в случае вызовов New(), GetMem() или конструкторов классов при невозможности распределения памяти. Соответствует RunTime Error 203.
      • EOutOfResources — происходит в том случае, когда невозможно выполнение запроса на выделение или заполнение тех или иных Windows ресурсов (например таких, как обработчики — handles).
      • EParserError — вызывается когда Delphi не может произвести разбор и перевод текста описания формы в двоичный вид (часто происходит в случае исправления текста описания формы вручную в IDE Delphi).
      • EPrinter — вызывается в случае любых ошибок при работе с принтером.
      • EProcessorException — предок исключений, вызываемых в случае прерывания процессора- hardware breakpoint. Никогда не включается в DLL, может обрабатываться только в “цельном” приложении.
      • EBreakpoint — вызывается в случае останова на точке прерывания при отладке в IDE Delphi. Среда Delphi обрабатывает это исключение самостоятельно.
      • EFault — предок исключений, вызываемых в случае невозможности обработки процессором тех или иных операций.
        • EGPFault — вызывается, когда происходит “общее нарушение защиты” — General Protection Fault. Соответствует RunTime Error 216.
        • EInvalidOpCode — вызывается, когда процессор пытается выполнить недопустимые инструкции.
        • EPageFault — обычно происходит как результат ошибки менеджера памяти Windows, вследствие некоторых ошибок в коде Вашего приложения. После такого исключения рекомендуется перезапустить Windows.
        • EStackFault — происходит при ошибках работы со стеком, часто вследствие некорректных попыток доступа к стеку из фрагментов кода на ассемблере. Компиляция Ваших программ со включенной проверкой работы со стеком <$S+>помогает отследить такого рода ошибки.
      • ESingleStep — аналогично EBreakpoint, это исключение происходит при пошаговом выполнении приложения в IDE Delphi, которая сама его и обрабатывает.
      • EPropertyError — вызывается в случае ошибок в редакторах свойств, встраиваемых в IDE Delphi. Имеет большое значение для написания надежных property editors. Определен в модуле DsgnIntf.pas.
      • EResNotFound — происходит в случае тех или иных проблем, имеющих место при попытке загрузки ресурсов форм — файлов .DFM в режиме дизайнера. Часто причиной таких исключений бывает нарушение соответствия между определением класса формы и ее описанием на уровне ресурса (например,вследствие изменения порядка следования полей-ссылок на компоненты, вставленные в форму в режиме дизайнера).
      • EStreamError — предок исключений, вызываемых при работе с потоками.
      • EFCreateError — происходит в случае ошибок создания потока (например, при некорректном задании файла потока).
      • EFilerError — вызывается при попытке вторичной регистрации уже зарегистрированного класса (компоненты). Является, также, предком специализированных обработчиков исключений, возникающих при работе с классами компонент.
        • EClassNotFound — обычно происходит, когда в описании класса формы удалено поле-ссылка на компоненту, вставленную в форму в режиме дизайнера. Вызывается, в отличие от EResNotFound, в RunTime.
        • EInvalidImage — вызывается при попытке чтения файла, не являющегося ресурсом, или разрушенного файла ресурса, специализированными функциями чтения ресурсов (например, функцией ReadComponent).
        • EMethodNotFound — аналогично EClassNotFound, только при несоответствии методов, связанных с теми или иными обработчиками событий.
        • EReadError — происходит в том случае, когда невозможно прочитать значение свойства или другого набора байт из потока (в том числе ресурса).
        • EFOpenError — вызывается когда тот или иной специфированный поток не может быть открыт (например, когда поток не существует).
      • EStringListError — происходит при ошибках работы с объектом TStringList (кроме ошибок, обрабатываемых TListError).

      Delphi, обладая прекрасными средствами доступа к данным, основывающимися на интерфейсе IDAPI, реализованной в виде библиотеки Borland Database Engine (BDE), включает ряд обработчиков исключительных ситуаций для регистрации ошибок в компонентах VCL работающим с БД. Дадим краткую характеристику основным из них:

      • EDatabaseError — наследник Exception ; происходит при ошибках доступа к данным в компонентах-наследниках TDataSet. Объявлено в модуле DB . Ниже приведен пример из Delphi On-line Help, посвященный этому исключению:

      Delphi Re-Raise Exception (передается в процедуре как параметр)

      Это образец исключения повторного рейза и хорошей работы

      и вот мой метод Custemize

      (1) → EConvertError → Сообщение об ошибке

      (2) → Исключение → Сообщение об ошибке

      когда я меняю последнюю строку, как этот код работает хорошо

      (1) → EConvertError → Сообщение об ошибке

      (2) → EConvertError → Сообщение об ошибке

      но я получаю «Нарушение доступа по адресу 00405F04 в модуле» Test.exe «. Читайте адрес 00000000.» после сообщений

      Как повысить такой же тип исключения, как базовое исключение

      Решение — это повышение TObject (AcquireExceptionObject);//

      Проблема, с которой вы сталкиваетесь, заключается в том, что если исключение попадает в исключающий блок, «конец» освободит экземпляр исключения, который вы только что подняли. Таким образом, следующий за исключением блока поймает уже выпущенный экземпляр Exception. Но вы можете предотвратить это, вызвав AcquireExceptionObject, который сделает вас владельцем экземпляра исключения.

      Поскольку вы не можете использовать raise; (System. @RaiseAgain), вы можете создать один и тот же экземпляр исключения с raise AcquireExceptionObject;

      Raise — Ключевое слово Delphi

      You would only raise an exception in literally exceptional circumstances. This is partly because of the resource and performance overheads incurred, but also because there are neater ways for application error handling, such as return codes from functions.

      On its own, Raise is used inside the Except clause of a Try statement. It simply re-raises the current exception for handling at a higher level in the application.

      Uses an new exception object to report an exception. Normally, you would use an Exception object, or an inherited Exception object, but you are not restricted to do so. The exception address is that of the raise statement.

      You can create the object at the time of the raise:

      Raise Exception.Create(‘Error happened’);

      Version 3 As for version 2, but overriding the address value of the exception.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL