2010-07-10 64 views
8

我通過檔案搜索,我發現了很多有關發件人是什麼以及爲什麼你應該使用該模式的問題,但我沒有看到任何關於自定義事件和類型如果發件人。創建自定義事件 - 對象發件人還是類型發件人?

說我創建了一個名爲Subscription的自定義類,它實現了ISubscription,並且我有一些名爲SubscriptionEventArgs的事件參數。如果訂閱有一個事件被稱爲Changed事件簽名Changed(ISubscription sender,SubscriptionEventArgs e)有什麼問題?

一些代碼來幫助推動問題:

public class SubscriptionEventArgs : EventArgs 
{ 
    // guts of event args go here 
} 

public interface ISubscription 
{ 
    event Action<ISubscription, SubscriptionEventArgs> Changed; 
} 

public class Subscription : ISubscription 
{ 
    public event Action<ISubscription, SubscriptionEventArgs> Changed; 

    private void OnChanged(SubscriptionEventArgs e) 
    { 
     if (Changed!= null) 
     { 
      Changed(this, e); 
     } 
    } 
} 

如果你只是鄙視用行動到位「事件處理程序」,那麼你可以做同樣的事情,但有一個自定義的通用「事件處理程序」。

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e); 

public class SubscriptionEventArgs : EventArgs 
{ 
    // guts of event args go here 
} 

public interface ISubscription 
{ 
    event EventHandler<ISubscription, SubscriptionEventArgs> Changed; 
} 

public class Subscription : ISubscription 
{ 
    public event EventHandler<ISubscription, SubscriptionEventArgs> Changed; 

    private void OnChanged(SubscriptionEventArgs e) 
    { 
     if (Changed!= null) 
     { 
      Changed(this, e); 
     } 
    } 
} 

針對漢族的一個樣本事件處理程序的要求:

public class SubscriptionCollection 
{ 
    // what is actually holding the subscriptions is not really relevant to the question 
    private List<ISubscription> _subscriptions; 

    public SubscriptionCollection() 
    { 
     _subscriptions = new List<ISubscription>(); 
    } 

    public void Add(ISubscription subscription) 
    { 
     subscription.Changed += new EventHandler<ISubscription, SubscriptionEventArgs>(Subscription_Changed); 
     _subscriptions.Add(subscription); 
    } 

    private void Subscription_Changed(ISubscription sender, SubscriptionEventArgs e) 
    { 
     // Now when the subscription changed event is being handled by the collection 
     // I don't have to look up the subscription in the list by some key and I don't 
     // have to cast sender to the correct type because the event handler was typed 
     // correctly from the beginning. 
    } 
} 

在列表中訂閱的查詢可能看起來微不足道,但如果我有非常大的數據集和工作新的數據量將通過實時流應用於應用程序。不得不停止並從列表中獲取參考或執行鑄造步驟的成本沒有意義。他們給了我們2.0中的泛型來解決這個問題,所以我不明白爲什麼我們沒有得到一個通用的事件處理程序,這讓我質疑泛型事件處理程序有什麼問題?

+0

我想如果添加了「where TEventArgs:EventArgs」,則第二塊更多。 – 2010-07-10 22:24:35

+0

只是一個提示,但如果你使用IObservable而不是你的接口類型的ISubscription,我認爲你會更好地遵循設計模式命名,並且可能會更清楚一目瞭然發生了什麼。 – 2010-07-15 05:17:00

回答

0

我實際上很困惑,爲什麼在設計.Net Framework v2時,MS並沒有提供EventHandler,只是描述方式 - TSenderTEventArgs作爲兩個通用參數。 (在v1和v1.1中,因爲他們沒有泛型,我完全理解爲什麼他們沒有製作數千個額外的委託類型來處理所有可能的事件。)如果我沒有記錯,仍然可以使用泛化處理程序聽一個更具體的事件:

public event EventHandler<Button, MouseDownEventArgs> MouseDown; 

private void ObservingMethod(object sender, EventArgs e) { } 

MouseDown += new EventHandler<Button, MouseDownEventArgs>(ObservingMethod); 

既然你不暴露觀察者可觀察到的,我看不出這可能是一個問題;一旦你進入事件處理程序,你只是防止需要進行類型檢查'以防萬一'。我認爲這將是一個很好的做法,儘管有些非標準,因爲MS決定不包括它。

正如我在註釋中提到上述,我寧願看到事件處理程序的如下定義,所以,你真的可以一直使用一個非常廣義的處理方法,因爲我的代碼示例:

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e) 
    where TEventArgs : EventArgs; 
+0

可能是因爲大多數這些事件都是在基類(Control - ButtonBase - ...)中聲明的,因此不會將Button類作爲發件人。 (現在還沒有協變性) – Stormenet 2010-07-13 12:19:53

+0

這很公平,但即使使用最具限制性的對象,即使它是一個抽象基類或者它所知道的接口也會有所幫助。例如,快速訪問而不用爲MouseDown事件進行CaptureMouse調用。而且,由於顯式委託包裝(如上所述,沒有泛型),我們仍然可以使用通用事件處理程序。 – 2010-07-14 13:38:34