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.
Тут есть элемент полиморфизма. Чтобы сработал механизм полиморфного конструирования, базовый тип класса, на который ссылается переменная типа ссылка на класс, должен обладать виртуальным конструктором.
Если базовый класс обладает виртуальным конструктором, то при обращении конструктору ссылки на класс будет выполнен метод, являющийся конструктором того класса, на который в данный момент ссылается ссылка на класс. Если же конструктор базового типа не виртуальный, то при обращении к конструктору ссылки на класс будет вызван конструктор фиксированного типа, указанного при объявлении переменной.