14.6.2 實現異常保護的TRY...FINALLY語句
上面的程序存在著潛在的危險,在實際應用過程中,可能因為某些原因使得對數據庫表的更新不能進行下去。如當程序試圖執行Post方法將修改後的記錄寫回磁盤時,而又因為某種原因磁盤沒有准備好,這時便出現了異常。當出現異常時,應用程序會暫停下來並且會彈出一對話框顯示有關的錯誤信息,在用戶單擊錯誤信息對話框之後,程序將繼續執行到某一個地方去,而這個地方常常不是用戶所能預料到的。在我們的程序中, 在執行Post方法之前,窗體中所有的部件與TTable部件都已失去聯系。因此,這種異常將導致窗體中顯示的數據和數據庫無關。
Object Pascal中的Try...Finally語句為我們解決上述異常問題提供了一個解決方法。在Delphi中仍然采用了這一語句用來處理異常問題。實際上,Try...Finally 語句是把兩組語句組合在一起。語句的Try部分包含了可能產生異常的程序代碼,Finally部分包含了即使發生了異常也必須執行的一條或多條語句。在本例中, Finally 部分只包含了EnableControls方法調用這一條語句,我們將前面的代碼改寫並組合進Try...Finally 語句:
with Table Do
begin
DisableControls;{在修改記錄的過程中,使其它部件無效}
Try;
First; {將記錄指針指向第一條記錄}
while not EOF do
begin
<讀取記錄的一個字段值到一個變量中>
<做適當的修改>
Edit; {將TTable部件置成編輯狀態}
<將修改後的字段值寫回到其對應的字段>
post; {將修改後的記錄寫回數據庫}
next; {修改下一條記錄}
end;
enablecontrols;
Finally;{出現異常時,執行下面的程序}
enablecontrols; {恢復其它部件的功能}
end; {結束Try...Finally語句}
end;
在保留字Try和Finally之間的代碼跟前面的代碼是一樣的,它們用於在記錄之間移動記錄指針並處理對記錄的修改,這一段代碼可能會出現異常,當異常發生時,我們想保證執行EnableControls,以便窗體中各控件恢復與 TTable 部件的聯系, 因此我們必須將EnableControls語句放在Finally和結束語句End之間。
在這裡要特別注意,請讀者們不要混淆了Try...Finally語句和Try...Except 語句。如果真正想在發生異常時采取相應的處理,就要使用Try...Except語句。Try... Finally語句只是用來處理當異常出現時,使應用程序執行Finally部分的語句,使程序繼續執行下去。Try...Except語句是實現異常處理,Try...Finally語句是實現異常保護。
有了上述這些概念,我們便可以提供這個例子的一些程序代碼,它涉及了所有這些內容。
程序清單:修改數據庫中的記錄
unit Unit26;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, DBGrids, ExtCtrls, DB, DBTables, Buttons;
type
TForm1 = class(TForm)
DataSource1: TDataSource;
customerTable: TTable;
Panel1: TPanel;
DBGrid1: TDBGrid;
Panel2: TPanel;
UpperCaseFirstAddBtn: TButton;
UpperCaseSecondAddBtn: TButton;
MixedCaseFirstAddBtn: TButton;
MixedCaseSecondAddBtn: TButton;
BitBtn1: TBitBtn;
procedure ForceCase(TargetField:String;ToUpper:Boolean);
procedure UpperCaseFirstAddBtnClick(Sender: TObject);
procedure MixedCaseFirstAddBtnClick(Sender: TObject);
procedure UpperCaseSecondAddBtnClick(Sender: TObject);
procedure MixedCaseSecondAddBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
const
upper=true;
Mixed=False;
{$R *.DFM}
Function IsUpper(ch:char):Boolean;
begin
If (ch>='A')and(ch<='Z')then
IsUpper:=true
else
IsUpper:=False;
end;
procedure TForm1.ForceCase(TargetField:String;ToUpper:Boolean);
var
WorkBuffer:string;
i:Integer;
begin
with customerTable do
begin
DisableControls;
TRY
First; {將記錄指針移到第一條記錄處 }
While not EOF do
begin
WorkBuffer:=FieldByName(TargetField).AsString;
If ToUpper then
for i:=1 to Length(WorkBuffer)do
WorkBuffer[i]:=UpCase(WorkBuffer[i])
else
begin
for i:=1 to Length(WorkBuffer) do
If IsUpper(WorkBuffer[i]) then
WorkBuffer[i]:=chr(ord(WorkBuffer[i])+32);
WorkBuffer[1]:=UpCase(WorkBuffer[1])
end;
Edit;
FieldByName(TargetField).AsString:=WorkBuffer;
post;
Next;
end;
Finally
enableControls;
end;
end;
end;
procedure TForm1.UpperCaseFirstAddBtnClick(Sender: TObject);
begin
ForceCase('Addr1',Upper);
end;
procedure TForm1.MixedCaseFirstAddBtnClick(Sender: TObject);
begin
ForceCase('Addr1',Mixed);
end;
procedure TForm1.UpperCaseSecondAddBtnClick(Sender: TObject);
begin
ForceCase('Addr2',Upper);
end;
procedure TForm1.MixedCaseSecondAddBtnClick(Sender: TObject);
begin
ForceCase('Addr2',Mixed);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
customerTable.open;
end;
end.