Какой самый элегантный способ поменять события при установке свойства? - PullRequest
1 голос
/ 05 октября 2009

Занимаясь разработкой на основе компонентов, я довольно часто это делаю:

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

Есть ли более изящный способ сделать это событие "swapout"?

(Конечно, всей проблемы можно было бы избежать, если бы foo был неизменным, но тогда я бы не получил никакой поддержки визуального дизайнера.)

Ответы [ 3 ]

5 голосов
/ 05 октября 2009

Я думаю, что ваша текущая реализация вполне приемлема. Это очень ясно и легко следовать.


Если вы хотите сократить код, так как вы делаете это много, вы можете создать метод, который это делает:

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 голос
/ 05 октября 2009

То, что вы делаете, хорошо, но я бы предпочел соглашение об отмене подписки на старые обработчики событий перед подпиской на новые, просто чтобы избежать любого потенциального "перекрытия", когда оба объекта могут попытаться обработать то же событие, если оно сработало из другого потока между вызовами.

Для незначительного улучшения вы можете обойтись без лишних скобок, чтобы сделать код более компактным и «аккуратным» (где «аккуратнее» в глазах смотрящего).

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 голосов
/ 05 октября 2009

Если вы не знаете, какие события были зарегистрированы в событии, и хотите полностью его очистить, вы можете сделать следующее:

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

Если вы знаете подписанного делегата, ваше текущее решение подойдет.

...