2009-10-05 64 views
1

做基於組件的開發,我發現自己相當頻繁這樣做:在設置屬性時,什麼是最優雅的交換事件的方式?

public class SomeClass 
{ 
    SomeOtherClass foo; 

    public SomeOtherClass Foo 
    { 
     get { return foo; } 
     set { 
      if (value != foo) { 
       if (value != null) { 
        // subscribe to some events 
        value.SomeEvent += foo_SomeEvent; 
       } 

       if (foo != null) { 
        // unsubscribe from subscribed events 
        foo.SomeEvent -= foo_SomeEvent; 
       } 

       foo = value; 
      } 
     } 
    } 

    void foo_SomeEvent(object sender, EventArgs e) 
    { 
     // do stuff 
    } 
} 

有沒有更優雅的方式做這個活動「換出」?

(當然,就可以避免整個問題,如果foo是不可改變的,但我不會得到任何可視化設計器的支持。)

回答

5

我認爲當前的實現是完全可以接受的。這是非常清楚和容易遵循。


如果你想縮短代碼,因爲你做這個有很多,你可以做,做它的方法:

private void SwapEventHandler<T>(T a, T b, Action<T> subscribe, Action<T> unsubscribe) 
    where T : class 
{ 
    if (a != null) 
     subscribe(a); 
    if (b != null) 
     unsubscribe(b); 
} 

然後,您可以寫:

if (value != foo) 
{ 
    SwapEventHandler(value,foo, (o) => o.SomeEvent += foo_SomeEvent, (o) => o.SomeEvent -= foo_SomeEvent); 
    foo = value; 
} 
+0

有時我發現自己在課堂上多次複製了這段代碼,並且開始看起來對於這麼簡單的操作來說很麻煩。嗯... – 2009-10-05 19:35:33

+0

是的,這是我錯過C++宏的情況... – 2009-10-05 19:41:15

+0

編輯爲了向您展示使用lambdas的更短版本 – 2009-10-05 19:41:51

1

你在做什麼很好,但我通常更喜歡在訂閱新訂單之前取消訂閱舊事件處理程序的約定,以避免任何潛在的「重疊」,其中如果兩個對象從調用之間的另一個線程中觸發,它們可以嘗試處理相同的事件。

對於邊際改進,可以省去不必要的大括號,以使代碼更緊湊和更「整齊」(其中「整數」在旁觀者眼中)。

 
set 
{ 
    if (value != foo) 
    { 
     if (foo != null) 
      foo.SomeEvent -= foo_SomeEvent; 
     if (value != null) 
      value.SomeEvent += foo_SomeEvent; 

     foo = value; 
    } 
} 

如果你是非法的,使用空引用(例如,通過使用參照「空Foo對象」,而不是一個空的),那麼你可以用完全的IFS分配:

 
set 
{ 
    if (value != foo) 
    { 
     foo.SomeEvent -= foo_SomeEvent; 
     value.SomeEvent += foo_SomeEvent; 
     foo = value; 
    } 
} 

在某些情況下,如果有許多屬性使用類似的對象/事件,那麼您也可以在(通用)輔助方法中實現交換代碼,以便在一個地方實現交換代碼,並且您的屬性都只需調用共享輔助方法。這隻會是有益的,如果你可以分享一個實現了許多特性,但:

 
set 
{ 
    Helpers.SetValueAndResubscribeFooSomeEvent(ref foo, value); 
} 
0

如果你不知道哪些事件已註冊的事件,並要完全地清除它,你可以做到以下幾點:

public class SomeOtherClass 
{ 
    public event EventHandler SomeEvent; 

    public void ClearSomeEvent() 
    { 
     foreach (EventHandler e in SomeEvent.GetInvocationList()) 
     { 
      SomeEvent -= e; 
     } 
    } 
} 

而且在SomeClass.Foo屬性setter:

if (foo != null) 
{ 
    // unsubscribe from subscribed events      
    foo.ClearSomeEvent();     
} 

如果你知道訂閱頻道的代表,你就是目前的解決方案是好的。

+0

我無法想象一個常見的情況,我想退訂我沒有我自己的訂閱。它似乎擊敗了訂閱機制的全部重點。 – 2009-10-05 20:17:15

相關問題