【问题标题】:How to avoid anonymous methods in "dynamic" event subscription?如何避免“动态”事件订阅中的匿名方法?
【发布时间】:2011-06-29 06:26:58
【问题描述】:

如何重构方法

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

如果我想避免在这里使用匿名方法?

【问题讨论】:

  • 这里的诀窍不是匿名方法——它是使用的闭包。想到的唯一另一种方法是创建一个新对象,该对象实现PropertyName 变量/属性或类似的以及OnPropertyChanged 事件处理程序并将其连接起来...... ick。
  • @pst:感谢您的评论。我想我对这里的内部结构仍然有些模糊。现在阅读csharpindepth.com/Articles/Chapter5/Closures.aspx。 =)

标签: c# anonymous-methods


【解决方案1】:

实现由 lambda 显式创建的闭包:

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

【讨论】:

  • 谢谢!这就是我上面的 lambda 在内部的真正含义吗?有趣的。 =)
【解决方案2】:

您可以通过为使用您所关注的实例字典的所有实例设置一个事件处理程序来处理此问题:

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 事件添加一个处理程序。

【讨论】:

  • 感谢您的回答!事实上,我可能会监听来自同一来源的多个属性。这种方法可能涉及更多的簿记,因为我不想通过在字典中引用来防止源被垃圾收集,但这可以管理。
【解决方案3】:

我不确定你到底想要达到什么目的,或者你为什么不想使用匿名方法,但你可以做一些更通用的事情:

    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 测试和目标方法组可以很容易地互换。您的事件处理程序也是强类型而不是匿名的。

【讨论】:

  • 我的同事不习惯匿名方法,所以我尽量避免使用它们。
  • 从技术上讲,PropertyChangedEventHandler 是一个专门用于侦听传播 PropertyChangedEventArgs 的事件的委托,因此无论何时使用强类型的 EventHandler,例如避免使用匿名方法,只要您只是传入一个方法组,它是一个函数(减去括号,bc 你不会立即调用它)你想在事件触发时调用它。我不会说有必要创建一个封装事件侦听的全新类 - 这就是 EventHandler 已经做的事情。
猜你喜欢
  • 2010-11-19
  • 2011-09-12
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多