Dot-Net

創建自定義事件 - 對象發送者還是類型化發送者?

  • July 15, 2010

我搜尋了檔案,發現了很多關於什麼是發件人以及為什麼應該使用該模式的問題,但我沒有看到任何關於自定義事件和發件人類型的資訊。

假設我正在創建一個名為 Subscription 的自定義類,它實現了 ISubscription,並且我有一些名為 SubscriptionEventArgs 的事件參數。如果 Subscription 有一個名為 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);
       }
   }
}

如果您只是鄙視使用動作代替“EventHandler”,那麼您可以做同樣的事情,但使用自定義的通用“EventHandler”。

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);
       }
   }
}

響應 Hans 對範例事件處理程序的請求:

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 中為我們提供了泛型來解決該問題,所以我不明白為什麼我們也沒有獲得泛型事件處理程序,這讓我質疑泛型事件處理程序有什麼問題?

我實際上很困惑,為什麼在設計 .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 決定不包括它。

正如我在上面的評論中所指出的,我更希望看到 EventHandler 的以下定義,以便您真的可以始終使用非常通用的處理程序方法,作為我的程式碼範例:

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

引用自:https://stackoverflow.com/questions/3220504