Finally

Try try

Finally

Try

J:=0;

For i:=1000 downto 0 do

J:= j + j div I; {деление на 0}

messageDlg(‘Total: ’,+IntToStr(j), mtInformation, [mbOK], 0);

screen.Cursos:=csDefault;

End;

В данном случае программа восстановит вид курсора в независимости от того, произошло исключение или нет.

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

Пример 3

Function Tform1.Btn3Click(sender:object);

Var I,j:integer;

Begin

Screen.Cursos:=czHourGlass;

J:=0;

For i:=1000 downto 0 do

J:= j + j div I; {деление на 0}

messageDlg(‘Total: ’,+IntToStr(j), mtInformation, [mbOK], 0);

screen.Cursos:=csDefault;

except

on E:EDivByZero do // E – временный объект исключения

begin

raise Exception.Create(‘ Ошибка в алгоритме ’);

end;

end;

end;

End;

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

Классы исключений

В дельфи исключения – это объекты, содержащие информацию, идентифицирующую ошибку и место её возникновения. В рассмотренных примерах осуществляется перехват исключения EDivByZero, определенного в библиотеке RTL среды Дельфи. Существует целый ряд такого рода исключений, относящихся к проблемам, возникающим в процессе выполнения программы. Кроме деления на 0 - неверное динамическое приведение типов, проблемы ресурсов – нехватка памяти, ошибки компонентов, неправильное использование индекса.

Пример.

Будет иллюстрировано как мы должны ориентироваться в иерархиях системы или в своих иерархиях.

Операция деления может генерировать два типа исключения – поэтому добавим в блок exception еще один оператор.

Function TMyClass.Repercent(A,B:integer):real;

Begin

Try

Result:= A/B * 100;

Except

On EDivByZero do {знаменатель равен 0}

Result:=0;

On EInvalidOp do

Result:=0;

End;

End;

Исключения - это объекты, все их типы является потомками базового класса Exception. Существует такая иерархия

Exception

EMathError

EDivByZero EInvalidOp

Таким образом, на основе правил совместимости типов в Object Pascal можно создать следующий обработчик:

Function TMyClass.Repercent(A,B:integer):real;

Begin

Try

Result:= A/B * 100;

Except

On EMathError do {все ошибки математич.вычислений}

Result:=0;

End;

End;

Создание пользовательской особой (исключительной ситуации)

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

Пример

Type

EArrayFull = class (Exception);

If MyArray.Full

Then reaise EArrayFull.Create(‘Массив заполнен’);

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

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

* Программисту не нужно заботиться об уничтожении объекта, созданного для обработки исключения – его удаление выполняется автоматически.

Tools>Debugger Options > Language Exceptions > o Stop on Delphi Exceptions

Синтаксис Дельфи для исключительных ситуаций представляет возможность для создания исключений …….

Procedure FT1.BtnClick (Sender: TObject);

Var F:TextFile; //new in Delphi

Ans:word;

Begin

AssignFile(F, Ed1.Text);

Try

Append

Try

Writeln(F, ‘….’), ….writeln(F, ‘…’);

Finally

Close(F);

End

Except

On E:EInOutError do

Begin

If E.ErrorCode=2 then{file not found}

Begin

Ans:=MessageDlg(‘Cannot find file ’+Edit1/Text+’.’#13+’would you like to create it?’, intError, [mbYes,mbNo],0)

If Ans=mrYes then FileCreate(Edit2.Text)

End

Else

Raise;{порождаем исключительную ситуацию заново}

End;

End;

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

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

*********** Для определения возникло ли исключение EInOutError использовалось значение ErrorCode <<<????

Такое поле не определено в базовом классе Exception. Оно является частью класса EInOutError

Type EInOutError = class (Exception)

Public

ErrorCode: integer;

End;

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

Пример:

Обычно не известно какая ситуация может привести к возникновению исключения, также невозможно заключить каждый фрагмент кода в блок try….except, можно воспользоваться следующим подходом: обработку всех исключений возложить на Дельфи и при этом вести журнал ошибок. А потом его можно проанализировать:

У объекта Application есть событе onException и компонент ApplicatonEvents.

На форму добавим компонент ApplicatonEvents и напишем обработчик события onException.

Procedure TF1.logException(Sender:Tobject; E:Exception);

Var FileName: string; logFile:TextFile;

Begin

FileName:=ChangeFileExt(Application.Exename. ‘.log’);

assignFile(LogFile, FileName);

if FileExists (FileName) then Append(logFile)

else ReWrite(LogFile); {открываем существующий файл или создаем новый}

writeln(LogFile, DateTimeToStr(Now)+’:’+E.Message);

if not CheckBoxSilent.Checked then Applivation.ShowException(E);

CloseFile(LogFile); // файл можно закрыть сразу или на событии onClose формы.

End;

   

_ _

[]_[] Ссылки на классы []_[]

Это элемент языка, который в процессе выполнения программы позволяет манипулировать не экземплярами классов а самими классами. Ссылка на класс – это не класс и не объект, это ссылка на тип данных.

Предположим, имеется класс TMyClass.

//Определим ссылку на этот класс

Type

TMyClassRef = class of TMyClass;

//Можно объявить переменные обоих типов

Var AClassRef: TMyClassRef;

AnObject: TMyClass;

Begin

AClassRef:= TMyClassRef;

AnObject:=TMyClass.Create;

End;

*Зачем нужны ссылки на класс?

-Они позволяют оперировать типами данных (классами) в процессе выполнения программы. Возможно использование ссылки на класс в любом выражении, в котором допускается упоминание типа данных. Таких случаев немного, но некоторые бывают очень полезны. В простейшем случае можно переписать код след.образом:

//Определим ссылку на этот класс

Type

TMyClassRef = class of TMyClass;

//Можно объявить переменные обоих типов

Var AClassRef: TMyClassRef;

AnObject: TMyClass;

Begin

AClassRef:= TMyClassRef;

AnObject:=TMyClass.Create;

//new

AClassRef:=TMyClass;

AnObject:=AClassRef.Create;

End;

*Здесь конструктор Create применен к ссылке на класс вместо настоящего класса.

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

Например:

Переменной типа ссылка на класс (TMyClassRef) можно присвоить как соответствующий ей конкретный класс, так и любой из его классов – потомков.

Type

TMyNewClass = class (TMyClass)

End;

……………………..

AClassRef:=TMyClass;

AClassRef:=TMyNewClass;

В библиотеках RealTypeLibrary и??? RealTimeLibrary??? определено много ссылок на класс.

…………

Type

TClass = class of TObject;

ExceptClass = class of Exception;

TComponentClass = class of TComponent;

TControlClass = class of TControl;

TFormClass = class of Tform;

……………

Ссылку на класс типа TClass можно использовать для хранения ссылки на любой класс Delphi (т.к. ссылается на TObject).

Ссылка TFormClass используется в исходном коде большинства проектов Дельфи. Метод CreateForm объекта Application требует в качестве параметра класс формы, которую нужно создать.

Application.CreateForm(Tform1, Form1); //1 - ссылка на класс, 2 – переменная, хранящая ссылку на созданный экземпляр объекта.

Кроме того ссылку на класс можно применять к методам связанного с ней класса(или наоборот????).

Принимая во внимание что каждый класс наследуется от TObject, любую ссылку на класс можно применять к его методам.

Создание компонентов при помощи ссылок на класс

Практическая польза механизма ссылок на класс в Дельфи заключается в возможности свободно оперировать типами данных в процессе выполнения программы.

При добавлении нового компонента на форму когда мы выбираем его из палитры компонентов, на самом деле мы выбираем тип данных и создаем объект этого типа данных.

Здесь механизм ссылок на классы обеспечивает полиморфизм в процессе конструирования объекта.

Пример:

TButton TEdit TLabel

Форма имеет 3 переключатели, при выборе одного из них и щелчке на форме создается компонент соответствующего класса. Имя такое же как и в Дельфи происходит.

Форма должна иметь поле типа ссылка на класс.

Private

Class: TControlClass;

Counter:integer;

При щелчке на каждом из переключателей поле в ClassRef сохраняется соответсующий тип данных.

Procedure TFrom1.RadioButtonBtnClick(sender);

Begin

ClassRef:=TButton;

End;

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

Обработаем событие onMouseDown, нам понадобятся X и Y.

Procedure TFrom1.FormMouseDown(x y);

Var newCtrl:TControl; myName:string;

Begin

newCtrl:=ClassRef.Create(self);

newCtrl.Visible:=False;

newCtrl.Parent:=Self;

newCtrl.hight=x; newCtrl.Top:=Y;

inc(Counter);

myName:=ClassRef.ClassName+IntToStr(Counter);

Delete(myName,1,1);

End;

//используем вместо типа данных ссылку на класс. Используем ссылку на класс вместо …TObject.

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

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: