12.3.5.1 定義異常對象類
異常是對象,所以定義一類新的異常同定義一個新的對象類型並無太大區別。由於缺省異常處理只處理從Exception或Exception子類繼承的對象,因而自定義異常類應該作為Exception或其它標准異常類的子類。這樣,假如在一個模塊中引發了一個新定義的異常,而這個模塊並沒有包含對應的異常響應,則缺省異常處理機制將響應該異常,顯示一個包含異常類名稱和錯誤信息的消息框。
下面是一個異常類的定義:
type
EMyException = Class(Exception) ;
12.3.5.2 自引發異常
引發一個異常,調用保留字raise,後邊跟一個異常類的實例。
假如定義:
type
EPasswordInvalid = Class(Exception);
則在程序中如下的語句將引發一個EPasswordInvalid異常:
If Password <> CorrectPassword then
raise EPasswordInvalid.Create('Incorrect Password entered');
異常產生時把System庫單元中定義的變量ErrorAddr的值置為應用程序產生異常處的地址。在你的異常處理過程中可以引用ErrorAddr的值。
在自己引發一個異常時,同樣可以為ErrorAddr分配一個值。
為異常分配一個錯誤地址需要使用保留字at,使用格式如下:
raise EInstance at Address_Expession;
12.3.5.3 自定義異常的應用舉例
下面我們給出一個利用自定義異常編程的完整實例。
兩個標簽框(Label1、Label2)標示對應編輯框的功能。編輯框PassWord和InputEdit用於輸入口令和數字。程序啟動時Label2、InputEdit不可見。當在PassWord中輸入正確的口令時,Label2、InputBox出現在屏幕上。此時Label1、PassWord隱藏。
設計時,令Label2、InputEdit的Visible屬性為False。通過設置PassWord的PassWordChar可以確定輸入口令時回顯在屏幕上的字符。
自定義異常EInvalidPassWord和EInvalidInput分別用於表示輸入的口令非法和數字非法。它們都是自定義異常EInValidation的子類。而EInValidation直接從Exception異常類派生。
下面是三個異常類的定義。
type
EInValidation = class(Exception)
public
ErrorCode: Integer;
constructor Create(Const Msg: String;ErrorNum: Integer);
end;
EInvalidPassWord = class(EInValidation)
public
constructor Create;
end;
EInvalidInput = class(EInValidation)
public
constructor Create(ErrorNum: Integer);
end;
EInValidation增加了一個公有成員ErrorCode來保存錯誤代碼。錯誤代碼的增加提供了很大的編程靈活性。對於異常類,可以根據錯誤代碼提供不同的錯誤信息;對於使用者可以通過截取錯誤代碼,在try...except模塊之外來處理異常。
從以上定義可以發現:EInvalidPassWord和EInvalidInput的構造函數參數表中沒有表示錯誤信息的參數。事實上,它們保存在構造函數內部。下面是三個自定義異常類構造函數的實現代碼。
constructor EInValidation.Create(Const Msg: String; ErrorNum: Integer);
begin
inherited Create(Msg);
ErrorCode := ErrorNum;
end;
constructor EInValidPassWord.Create;
begin
inherited Create('Invalid Password Entered',0);
end;
constructor EInValidInput.Create(ErrorNum: Integer);
var
Msg: String;
begin
case ErrorNum of
1:
Msg := 'Can not convert String to Number';
2:
Msg := 'Number is out of Range';
else
Msg := 'Input is Invalid';
end;
inherited Create(Msg,ErrorNum);
end;
對於EInvalidInput,ErrorCode=1表示輸入的不是純數字序列,而ErrorCode=2表示輸入數值越界。
口令檢查是用戶在PassWord中輸入口令並按下回車鍵後開始的。實現代碼在PassWord的OnKeyPress事件處理過程中:
procedure TForm1.PassWordKeyPress(Sender: TObject; var Key: Char);
const
CurrentPassWord = 'Delphi';
begin
if Key = #13 then
begin
try
if PassWord.text <> CurrentPassWord then
raise EInvalidPassWord.Create;
Label2.Visible := True;
InputEdit.Visible := True;
InputEdit.SetFocus;
PassWord.Visible := False;
Label1.Visible := False;
except
on EInvalidPassWord do
begin
PassWord.text := '';
raise;
end;
end;
Key:=#0;
end;
end;
同樣,在InputEdit的OnKryPress事件處理過程中實現了輸入數字的合法性檢查:
procedure TForm1.InputEditKeyPress(Sender: TObject; var Key: Char);
var
Res: Real;
Code: Integer;
begin
if Key = #13 then
begin
try
val(InputEdit.text,Res,Code);
if Code <> 0 then
raise EInValidInput.create(1);
if (Res > 1) or (Res < 0) then
raise EInValidInput.create(2);
MessageDlg('Correct Input', mtInformation,[mbOk], 0);
Key := #0;
except
on E:EInValidInput do
begin
InputEdit.text := '';
MessageDlg(E.Message, mtWarning,[mbOk], 0);
end;
end;
end;
end;
由於異常響應後即被清除,所以要顯示異常信息,需要另外的手段。在以上兩段程序中我們采用了兩種不同的方法:在口令合法性檢查中,利用異常重引發由系統進行缺省響應;在輸入數字合法性檢查中,通過異常實例來獲取異常信息並由自己來顯示它。
以上所舉的是一個非常簡單的例子,但從中已可以發現:使用自定義異常編程,為程序設計帶來了很大的靈活性。