设置属性时更换事件的最优雅方法是什么?

时间:2009-10-05 19:14:42

标签: c# events event-handling components

进行基于组件的开发,我发现自己经常这样做:

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是不可变的,那么可以避免整个问题,但是我不会得到任何视觉设计师支持。)

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

你正在做的事情很好,但我通常更喜欢在订阅新事件之前取消订阅旧事件处理程序的惯例,只是为了避免两个对象都试图处理的任何潜在的“重叠”如果它从调用之间的另一个线程触发,则为同一事件。

为了获得微小的改进,您可以省去不必要的大括号,使代码更紧凑,更“整洁”(“更整洁”在旁观者眼中)。

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

        foo = value;
    }
}

如果你使用空引用是非法的(例如通过使用对“Null Foo对象”的引用而不是null),那么你可以完全省略ifs:

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

在某些情况下,您有许多属性处理类似的对象/事件,您可能还可以在(通用)帮助器方法中实现交换代码,以便在一个位置实现实现,并且您的属性都只是调用共享帮助程序方法。如果您可以共享许多属性的一个实现,那么这只会有好处:

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

答案 2 :(得分:0)

如果您不知道哪些事件已在活动中注册,并且想要完整地清除它,您可以执行以下操作:

public class SomeOtherClass
{
    public event EventHandler SomeEvent;

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

在SomeClass.Foo属性设置器中:

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

如果您确实知道所描述的代表,那么您当前的解决方案就可以了。