рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Создание собственных исключений

Создание собственных исключений - раздел Информатика, Создание собственных исключений Кроме Использования Стандартных Классов Исключений Программист Может Самостоя...

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

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

raise EMathError.Create(' ') ;

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

var E: EMathError;

begin

E := EMathError.Create С');

raise E;

end;

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

if С = 0 then

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

else

А := В/С;

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

Пример.

Пусть надо вычислять функцию У = Х*Х , причем должно выполняться условие Х >= 0, иначе должна возникать ИС и выдаваться сообщение 'Х<5'. Для этогосоздадим собственное исключение Ехх.

В разделе type после объявления класса Tform1(после end) запишем

Type

Exx = class(Exception);

Далее создаем процедуру для обработки кнопки Button1:

 

procedure TForm1.Button1Click(Sender: TObject);

var

x,y:integer;

Sx,sy:String;

begin

Sx:=Edit1.Text;

x:=StrToInt(sx);

If x<5 Then

RAISE exx.CreateFmt('Х меньше 5',[x]);

y:=x*x;

sy:=IntToStr(y);

Edit2.Text:=sy;

end;

end.

 

5.19.8. Использование исключительных ситуаций

 

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

1. Если ситуация возникла внутри блока try..except, то там она и будет обработана. Если ИС "продвинута" дальше при помощи оператора raise, а также если она возникла в блоке try. .finally, обработка продолжается.

2. Если программистом определен обработчик события Application.onException, то он получит управление. Обработчик объявлен следующим образом:

TExceptionEvent = procedure (Sender: TObject; E: Exception) of object;

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

Пункты 2 и 3 реализуются в методе TAppiication.HandieException. Собственно, выглядят они следующим образом:

if not (ExceptObject is EAbort) then

if Assigned(FOnException) then

FOnException(Sender, Exception(ExceptObject))

else

ShcwExceptior. (Exception(ExceptObject));

Обработчик onExceptiоn нужен, если требуется выполнять одно и то же действие в любой исключительной ситуации, возникшей в вашем приложении. К примеру, назвать себя, указать координаты для обращения или предупредить, что это еще бета-версия.

program Project!;

uses

Forms,

SysUtils, //добавлено вручную — там описан класс Exception Dialogs,

Unitl in 'Unitl.pas' {Forml};

{$R *.RES}

type

TExceptClass = class

public

procedure GlobalExceptionHandler(Sender: TObject; E:Exception);

end;

procedure TExceptClass.GlobalExceptionHandler(Sender: TObject;

E:Exception);

begin

ShowMessage('Произошла исключительная ситуация ' + E.ClassName

+ ': ' + E.Message

+ #13#10'Свяжитесь с разработчиками по тел. 222-33-44');

end;

begin

with TExceptClass.Create do

begin

Application.OnException := GlobalExceptionHandler;

Application.Initialize;

Application.CreateFormfTForml, Forml);

Application.Run;

Free;

end;

end.

Здесь класс TExceptClass создается только для того, чтобы быть носителем метода GiobaiException. Обработчик любого события — метод, и он должен относиться к какому-либо объекту. Поскольку он здесь нужен еще до инициализации форм приложения и других его составных частей, то и объект класса TExceptClass создается первым. Теперь пользователь знает, что благодарить за неожиданности нужно по указанному в сообщении об ошибке телефону разработчиков.

Примечание

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

Но как "пощупать" переданный при исключительной ситуации объект? Обычная конструкция

on EExceptionType do...

указывает на класс объекта, но не на конкретный экземпляр. Если во время обработки требуется доступ к свойствам этого экземпляра, его нужно поименовать внутри on..do, указав перед именем класса некий идентификатор:

on EZD: EZeroDivide do EZD.Message := 'Деление на ноль!';

Здесь возникшее исключение выступает под именем EZD. Можно изменить его свойства и отправить дальше:

var APtr : Pointer;

Forml : TForm;

try

APtr := Forml;

with TObject(APtr) as TBitmap do;

except

on EZD: EInvalidCast do EZD.Message :=. EZD.Message + 'xa-xa!';

Raise;{ теперь обработка будет сделана в другом месте }

end;

Но как поименовать исключительную ситуацию, не попавшую ни в одну из директив on..do? Или, может быть, в вашем обработчике вообще нет on. .do, а поработать с объектом надо? Описанный выше путь здесь не подходит. Для этих случаев есть пара системных функций Exceptobject и ExceptAddr. К сожалению, эти функции инициализируются только внутри конструкции try..except; в try..finally работать с объектом— исключительной ситуацией не представляется возможным.

 

5.19.9. Коды ошибок в исключительных ситуациях

 

Если приложение уже готовится к продаже, то пора задуматься о присвоении числовых кодов ошибкам, возникающим в нем. Сообщение типа "Exception EZeroDivide in module MyNiceProgram at addr $0781BABO" годится для разработчика, пользователя же оно повергнет в полный ступор. Гораздо грамотнее дать ему уже "разжеванную" информацию и, в том числе, числовой код. Один из путей решения этой проблемы — размещение сообщений об ошибках в ресурсах программы

"Классический" способ поместить текст в файл ресурсов :

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

2. Файл обрабатывается компилятором ресурсов brcc32.exe (находится в папке bin в структуре папок Delphi). На выходе образуется одноименный файл с расширением res.

3. Файл включается в программу указанием директивы $R, например

{$R mystrings.res}.

Чтобы совместно использовать константы-номера ошибок в файле ресурсов и в коде на Delphi, вынесем их в отдельный включаемый файл с расширением inc:

const

IOError = 1000;

FileOpenError = IOError + 1;

FileSaveError = IOError + 2;

InternetError = 2000;

NoConnecticnError = InternetError + 1;

ConnectionAbortedError = InternetError + 2;

Взглянув на файл, вы увидите, что ошибки в нем сгруппированы по категориям. Советуем вам поступить так же, разделив константы категорий промежутком в 1000 или даже 10 000.

Сам файл ресурсов может выглядеть так:

#include "strids.inc" STRINGTABLE

{

FileOpenError, "File Open Error"

FileSaveError, "File Save Error"

NoConnectionError, "No Connection"

ConnectionAbortedError, "Connection Aborted"

}

Извлечь строку из ресурсов можно несколькими способами, самый простой из них — просто по числовому идентификатору, переданному в функцию Loadstr (модуль SysUtils). Код

ShowMessage(LoadStr(NoConnectionError) ) ;

покажет сообщение "NO connection".

Если же строка используется при возбуждении ИС, то место идентификатору—в перекрываемом конструкторе Exception.createRes, один из вариантов которого работает подобно функции Loadstr:

if FileOpent'c:myfile.txt", fmOpenRead) = INVALID_HANDLE_VALUE then

raise EMyException.CreateRes(FileOpenError) ;

Таким образом, решена половина проблемы: возможным исключительным ситуациям присвоены номера, им в соответствие поставлен текст. Теперь о второй половине — как в обработчике ИС этот номер использовать.

Ясно, что нужно объявить свой класс ИС, включающий в себя свойство-код

ошибки.

EExceptionWithCode = class(Exception)

private

FErrCode : Integer;

public

constructor CreateResCode(ResStringRec: PResStringRec);

property ErrCode: Integer read FErrCode write FErrCode;

end;

Тогда любой обработчик сможет к нему обратиться:

if E is EExceptionWithCode then

ShowMessage('Error code: ' + IntToStr(EExceptionWithCode(E).ErrCode) +

#13*10

+ 'Error text: ' + E.Message);

Присвоить свойству ErrCode значение можно двумя способами:

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

constructor EExceptionWithCode.CreateResCode(Ident: Integer);

begin

FErrCode := Ident;

inherited CreateRes(Ident);

end;

2. Присвоить значение свойства в промежутке между созданием объекта ИС и его возбуждением:

var E: EExceptionWithCode; begin

E := EExceptionWithCode.CreateRes(NoConnectionError);

E.ErrCode := NoConnectionError;

Raise E;

end;

Но как быть тем, кто заранее не заготовил файл ресурсов, а работает со строками, описанными в PAS-файлах? Если вы используете оператор resourcestring, то помочь вам можно.

Начнем с рассмотрения ключевого слова resourcestring. Вслед за ним описываются текстовые константы. Но, в отличие от ключевого слова const, эти константы размещаются не в сегменте данных программы, а в ресурсах, и подгружаются оттуда по мере необходимости. Каждая такая константа воспринимается и обрабатывается как обычная строка. Но за каждой из них на самом деле стоит такая структура:

PResStringRec = ^TResStringRec;

TResStringRec = packed record

Module: ^Cardinal;

Identifier: Integer;

end;

Если вы еще раз посмотрите на список конструкторов объекта Exception, вы увидите, что те из них, которые работают с ресурсами, имеют перегружаемую версию с параметром типа pResstringRec, они предназначены для строк из resourcestring. А взглянув на приведенную выше структуру, вы увидите в ней поле identifier. Среда Delphi берет на себя заботу об уникальных идентификаторах ресурсных строк.. Номера назначаются компилятором, начиная от 65 535 (SmallInt (-D) и ниже (если рассматривать номер как тип (SmallInt, то выше): 65 534, 65 533 и т. п. Сначала в этом списке идут несколько сотен resourcestring-констант, описанных в VCL (из модулей, чье имя заканчивается на const или consts: sysconst, DBConsts и т. п.). Затем очередь доходит до пользовательских констант (рис. 3.3).

С одной стороны, отсутствие лишних забот — это большой плюс; с другой стороны, разработчик не может задать строкам те номера, какие хочет.

Все остальное почти ничем не отличается от работы с "самодельными" ресурсами. Так выглядит перегружаемая версия конструктора нашего объекта EExceptionWithCode:

constructor EExceptionWithCode.CreateResCode(ResStringRec:PResStringRec);

begin

FErrCode := ResStringRec^.Identifier;

inherited CreateRes(ResStringRec);

end;

А так — возбуждение самой ИС:

resourcestring sErrorl = 'Error 1';

Raise EExceptionWithCode.CreateResCode

(PResStringRec(@sErrorl));

Результат обработки показан на рис. 3.3.

Рис. 3.3.Результат обработки ИС типа EExceptionWithCode

 

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

 

Если вы внимательно просмотрели код системной процедуры HandieException, то увидели там упоминание класса EAbort. ИС EAbort служит единственным — и очень важным — исключением из правил обработки. Она называется "тихой" (Silent) и отличается тем, что для нее обработка по умолчанию не предусматривает вывода сообщений на экран. Естественно, все сказанное касается и порожденных от нее дочерних объектных классов.

Применение EAbort оправдано во многих случаях. Вот один из примеров. Пусть разрабатывается некоторая прикладная программа или некоторое семейство объектов, не связанное с VCL. Если в них возникает ИС, то нужно как-то известить об этом пользователя. А между тем прямой вызов для этого функции showMessage или даже MessageBox не всегда оправдан. Для маленькой и компактной динамической библиотеки не нужно тащить за собой громаду VCL. С другой стороны, в большом и разнородном проекте нельзя давать каждому объекту или подпрограмме самой общаться с пользователем. Если их разрабатывают разные люди, такой проект может превратиться в вавилонскую башню. Тут и поможет EAbort. Эта исключительная ситуация не создается системой — ее должен создавать и обслуживать программист.

Применение EAbort — реальная альтернатива многочисленным конструкциям if..then и тем более (упаси боже!) goto. Эта ИС не должна подменять собой другие, вроде ошибки выделения памяти или чтения из файла. Она нужна, если вы сами видите, что сложились определенные условия и пора менять логику работы программы.

If LogicalCondition then Raise EAbort.Create('Condition 1');

Если не нужно определять сообщение, можно создать EAbort и проще — вызвав процедуру Abort (без параметров), содержащуюся в модуле SYSUTILS.PAS.

Функция Assert

Эта процедура и сопутствующая ей ИС EAssertionFailed специально перенесены в Object Pascal из языка С для удобства отладки. Синтаксис ее прост:

procedure Assert(expr : Boolean [; const msg: string]);

При вызове функции проверяется, чему равно значение переданного в нее булевого выражения ехрr. Если оно равно True, то ровным счетом ничего не происходит. Если же оно равно False, создается ИС EAssertionFailed. Все это было бы довольно тривиально с точки зрения уже изученного, если бы не два обстоятельства:

1. Предопределенный обработчик EAssertior.Failed устроен таким образом, что выдает не шестнадцатеричный адрес ошибки, а имя файла с исходным текстом и номер строки, где произошла ИС, как показано на рис. 3.4.

Рис. 3.4.Окно сообщения обработчика исключительной ситуации EAssertionFailed

2. При помощи специальной директивы компилятора {$ASSERTIONS ON/OFF} (или, что то же самое, {$с+}/{$с-}) возникновение этих ИС можно централизованно запретить. То есть в отлаживаемом коде в режиме {$с+} можно расставить вызов Assert во всех сомнительных и проверяемых местах. Когда же придет время генерации конечного варианта кода, переключением директивы на {$c-} весь отладочный вывод запрещается.

Резюме

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

В Delphi для обработки исключительных ситуаций используются специальные конструкции языка Object Pascal и классы на основе базового класса исключительных ситуаций Exception.

– Конец работы –

Эта тема принадлежит разделу:

Создание собственных исключений

Параллельно с блоком try except в языке существует и try finally Он соответствует случаю когда необходимо возвратить выделенные программе... try... lt Оператор gt...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Создание собственных исключений

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

Эта работа не имеет других тем.

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги