Effective C# 重寫優於事件處理器

許多.net類庫中的類都提供了兩種不同的處理事件句柄的方法。既可以爲其添加事件,也可以重寫其基類的事件抽象方法。爲什麼要爲同一件事提供兩種不同的方法呢?這是爲了對應不同的情況。在實現派生類的時候,更好的選擇是重寫基類中的抽象方法。

      假設我們現在正在編寫一個windows應用程序,這個程序需要對鼠標按鍵按下的事件做出響應。在自定義的Form類中,我們可以選擇重寫OnMouseDown()事件:

    public class MyForm : Form
    
{
        
protected override void OnMouseDown(MouseEventArgs e)
        
{
            
try
            
{
                HandleMouseDown(e);
            }

            
catch
            
{
                
//error
            }

            
base.OnMouseDown(e);
        }

    }

 

或者添加事件句柄:

 

    public class MyForm : Form
    
{
        
public MyForm()
        
{
            
this.MouseDown += new MouseEventHandler(MyForm_MouseDown);
        }


        
void MyForm_MouseDown(object sender, MouseEventArgs e)
        
{
            
try
            
{
                HandleMouseDown(e);
            }

            
catch
            
{
                
//error
            }

        }

    }

 

 

這裏推薦使用第一種方法。一旦事件句柄拋出異常,不會再有其他的事件句柄被調用。這避免了一些錯誤代碼繼續被調用而引發的問題。通過重寫受保護的虛方法,我們的句柄可以第一個被調用。基類中虛函數負責其他相關句柄的調用。這意味着如果需要調用那些事件句柄(一般來說是需要的),就要調用基類的虛函數。在有些特殊情況下我們需要替換基類的默認行爲,可能不需要調用任何原有的事件句柄。雖然我們不能保證所有的事件句柄都被執行,因爲其可能會拋出異常,但是我們可以保證派生類的行爲是正確的。

      使用override比添加事件句柄高效的多。在 條款 22中展示了System.Windows.Forms.Control類是如何存儲句柄時間並將其對應到每一個事件的。這種事件機制由於要檢查事件句柄將造成更多的消耗。事件句柄列表中的每個方法都需要執行。相比重寫虛方法,通過事件處理會消耗更多的時間。

      如果這還不足以說服你,咱們可以再回頭看一下開始時候的代碼。哪一種更清晰?重寫虛方法只需要維護一個函數就可以達到檢查和修改的目的。而事件機制需要兩個維護點:事件句柄函數和事件綁定代碼。其中任何一點都可能造成整體功能上的失敗。一個函數顯然要簡單些。

      這些就是使用重寫和不是事件句柄的理由。但是.net設計者之所以會提供事件也是有其理由的。他們不會做無用的工作。這種重寫是針對派生類的。除此之外的情況我們必須使用事件機制。例如我們經常需要爲Form添加一個按鈕的點擊事件。這個事件由按鈕引發,在form中處理。當然我們可以搞一個自定義按鈕,然後在裏面重寫點擊的虛方法,但這太繁瑣了,爲了處理一個事件,需要創建一個自定義的按鈕類,完全是在給自己找麻煩。而使用事件機制就非常的簡單。這也是.net framework設計者在設計事件機制的一個理由。

      另外一個理由是事件的綁定是在運行期進行的。我們可以更加靈活的處理事件,在運行時爲其綁定不同的事件。假設我們正在編寫一個繪圖程序,點擊鼠標可能是畫線的開始,也可能是選取某個對象。我們可以在使用者切換模式的時候來切換這些事件。而且,我們可以爲同一個事件添加多個事件句柄。

      當我們創建派生類時,應當使用重寫虛函數的方法來處理事件。這樣便於維護也更加高效。其他情況則應該使用事件句柄。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章