Wolfgang Chien's Homepage | Delphi學習筆記 - 問答篇 |
在 Delphi1.0的user's guide 中 用到 Sender這個通用的prarmeter有時要用 sender as ClassRef 的形式 有時只用Sender就可以, 如
with Sender as TButton do begin Caption := '&Ok'; OnClick := OkClick; end; if Sender = Button1 then AboutBox.Caption := 'About ' + Application.Title else AboutBox.Caption := ;
也有人寫成
case TButton(sender).Tag of
以上這三種形式到底適用在什麼情況下呢?
這是個觀念的問題, 我嘗試解釋看看, 不對與不足的地方還請其他網友不吝指正:
(Sender as TButton) 與 TButton(Sender) 都是 Typecasting,只是語法不同罷了, 因此, 寫成 (Sender as TButton).Caption := 'Test';或者 TButton(Sender).Caption := 'Test'; 結果都一樣
針對個別物件個別事件撰寫事件處理程序, 並不需判定 Sender為何, 因為很明顯的 Sender 便是這個正在撰寫的物件, 但是在多個物件共用一個事件處理程序的情況下, Sender 是誰(誰發生OnClick 事件)的判斷就有其必要性
if Sender = Button1 的寫法是直接判定Sender是不是 Button1這個物件, 但是如果按鈕有 64 個, 寫 64 個 if 敘述恐怕會累死人的...
因此, 以類別的判定取代個別物件的副本(instance)的判定, 應是比較簡明的作法, 於是, 我們可以寫成 Sender is TButton, 為真時, 以上述型別轉換的方式 --- TButton(Sender).XXXX 撰寫, 就可以大輻簡化程式, 畢竟,同屬 TButton 的物件, 都有相同的屬性(屬性值不一定相同), 不是嗎?
值得注意的是, Sender is (Class Name) 的 Class Name 判斷是會牽涉到父階的繼承關係的, 例如: Button1 是 Button,Button2是 TBitBtn, 這樣的話:Button1 is TButton 為真, Button2 is TButton 也是真, 因為TBitBtn 繼承自 TButton, 也就是說, 球是球, 籃球也是球. 應用這個觀念, 下列的程式:
if ActiveControl is TDBEdit then (ActiveControl as TDBEdit).CutToClipboard else if ActiveControl is TDBMemo then (ActiveControl as TDBMemo).CutToClipboard;
如果改成:
if ActiveControl is TCustomMemo then TCustomMemo(ActiveControl).CutToClipboard;
程式的執行效率就更好了, 因為 TDbEdit 與 TDbMemo 的共同父階是 TCustomMemo, 而 TCustomMemo 也有 CutToClipboard 方法
此外, (Sender as TButton) 在型別轉換時若發生錯誤,會舉發例外訊息, 而 TButton(Sender)則強制轉型不會舉發例外報告. 像是下例的寫法,雖然沒有例外訊息, 但在邏輯上畢竟是不正確的; 換句話說, 語法錯誤是沒有, 但潛藏的錯誤仍然危險:
// 假設 Sender 事實上是 TButton 型的物件
TPanel(Sender).BevelWidth := 2;
所以, 有一些人主張保險起見應該寫成:
// 假設 Sender 事實上是 TButton 型的物件
(Sender as TPanel).BevelWidth := 2;
以便在不正確型別強轉換時提示錯誤的發生.
但話說回來了, 型別轉換到底合不合理是程式發展人員的責任, 將 TButton轉型成TPanel就說不通. 不管用哪一種寫法, 在轉換前作一下判斷是應該的,所以, 您可能會常看到類似如下的寫法:
if ActiveControl is TCustomMemo then TCustomMemo(ActiveControl).CutToClipboard;
用意即在先作一次判斷. 當然, 交給例外處理機制接管也行, 但畢竟是打擾了程式的執行流程, 有點令人討厭, 我是認為 Except 應該是在「承認理性是局部的」與「程式可讀性」等兩個前提下的後援, 可能的話, 能在事前加以判斷是比較好的.
準此, 則下列的寫法就很經典了:
if Sender is TPanel then (Sender as TPanel).BevelWidth := 2;
首頁 | 學習筆記 | 主題公園 | 軟體下載 | 關於本站 | 討論信群 | 相約下次 |