2009-10-05 62 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

相关问题