許多.net類庫中的類都提供了兩種不同的處理事件句柄的方法。既可以爲其添加事件,也可以重寫其基類的事件抽象方法。爲什麼要爲同一件事提供兩種不同的方法呢?這是爲了對應不同的情況。在實現派生類的時候,更好的選擇是重寫基類中的抽象方法。
假設我們現在正在編寫一個windows應用程序,這個程序需要對鼠標按鍵按下的事件做出響應。在自定義的Form類中,我們可以選擇重寫OnMouseDown()事件:
{
protected override void OnMouseDown(MouseEventArgs e)
{
try
{
HandleMouseDown(e);
}
catch
{
//error
}
base.OnMouseDown(e);
}
}
或者添加事件句柄:
{
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設計者在設計事件機制的一個理由。
另外一個理由是事件的綁定是在運行期進行的。我們可以更加靈活的處理事件,在運行時爲其綁定不同的事件。假設我們正在編寫一個繪圖程序,點擊鼠標可能是畫線的開始,也可能是選取某個對象。我們可以在使用者切換模式的時候來切換這些事件。而且,我們可以爲同一個事件添加多個事件句柄。
當我們創建派生類時,應當使用重寫虛函數的方法來處理事件。這樣便於維護也更加高效。其他情況則應該使用事件句柄。