Как избежать анонимных методов в "динамической" подписке на события?

Как я мог реорганизовать метод

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source,
                                          string propertyName)
{
    source.PropertyChanged += (o, e) =>
    {
        if (e.PropertyName == propertyName)
            MyMagicMethod();
    };
}

если бы я хотел избежать использования здесь анонимного метода?

3 ответа

Решение

Реализуйте замыкание, которое неявно создается лямбда-выражением явно:

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source,
                                          string propertyName)
{
    var listener = new MyPropertyChangedListener(propertyName);
    source.PropertyChanged += listener.Handle;
}

class MyPropertyChangedListener
{
    private readonly string propertyName;

    public MyPropertyChangedListener(string propertyName)
    {
        this.propertyName = propertyName;
    }

    public void Handle(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == this.propertyName)
        {
            // do something
        }
    }
}

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

private Dictionary<INotifyPropertyChanged, List<string>> sourceMap =
    new Dictionary<INotifyPropertyChanged, List<string>>();

private void ListenToPropertyChangedEvent(INotifyPropertyChanged source,
                                            string propertyName)
{
    if (sourceMap.ContainsKey(source))
        sourceMap[source].Add(propertyName);
    else
    {
        source.PropertyChanged += source_PropertyChanged;
        sourceMap[source] = new List<string> { propertyName };
    }
}

void source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var source = sender as INotifyPropertyChanged;
    var list = sourceMap[source];
    if (list.Contains(e.PropertyName))
        MyMagicMethod();
}

В этой версии нет проверки или удаления ошибок, но она демонстрирует технику. Это особенно ценно, если вы слушаете несколько свойств из одного источника. Это потому, что он добавляет только один обработчик к PropertyChanged событие в каждом случае.

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

    private PropertyChangedEventHandler GetHandler
      (Func<PropertyChangedEventArgs, bool> test, Action toInvoke)
    {
        return new PropertyChangedEventHandler(
            (o, e) => 
            {
               if (test(e))
                toInvoke(); 
            }); 
    }

Тогда вы можете использовать это так:

  source.PropertyChanged += GetHandler                
            (
                p => p.PropertyName == propertyName, MyMagicMethod
            ); 

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

Другие вопросы по тегам