c# - 在静态方法(扩展方法)中取消订阅匿名事件处理程序

标签 c# event-handling extension-methods static-methods

我有一个扩展方法来订阅实现 INotifyPropertyChanged 的对象的 PropertyChanged 事件。

我希望事件只触发一次。不多了。

这是我的方法。

public static void OnPropertyChanged<T>(this  INotifyPropertyChanged target, string    propertyName, Action action)
{
    if (target == null)
    {
        return;
    }

    PropertyChangedEventHandler handler = (obj, e) =>
    {

        if (propertyName == e.PropertyName)
        {
            action();
        }

    };


    target.PropertyChanged -= handler;
    target.PropertyChanged += handler;

}

但它不起作用。我无法删除事件处理程序,因此每次调用此方法时都会触发事件。

我尝试了一种不同的方法。不使用匿名方法,而是使用更传统的方法,例如:

public static void OnPropertyChanged<T>(this  INotifyPropertyChanged target, string    propertyName, Action action)
{
    if (target == null)
    {
        return;
    }

    target.PropertyChanged -= target_PropertyChanged;
    target.PropertyChanged += target_PropertyChanged;

}

static void target_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //do stuff here
    }

而且效果很好。该事件只触发一次,但我还需要 Action 参数。我不能用这种方法使用它。

解决这个问题的任何解决方法或不同的方法?静态方法中的匿名方法有什么奇怪的地方吗?

提前致谢。

最佳答案

这是使用匿名方法作为事件处理程序的限制。它们不能像普通方法(从技术上讲是通过方法组转换自动创建的委托(delegate)实例)那样被删除,因为匿名方法被编译到编译器生成的容器类中,并且每次都会创建该类的新实例。

为了保留操作参数,您可以创建一个容器类,其中包含您的事件处理程序的委托(delegate)。该类可以在您正在使用的其他类的内部声明为私有(private) - 或设为内部类,也许在“Helpers”命名空间中。它看起来像这样:

class DelegateContainer
{
    public DelegateContainer(Action theAction, string propName)
    {
         TheAction = theAction;
         PopertyName = propName;
    }

    public Action TheAction { get; private set; }
    public string PropertyName { get; private set; }

    public void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
    {
        if(PropertyName == e.PropertyName)
            TheAction();
    }
}

然后,在您的类中创建并存储对容器的引用。您可以创建一个静态成员 currentContainer,然后像这样设置处理程序:

private static DelegateContainer currentContainer;

public static void OnPropertyChanged<T>(this  INotifyPropertyChanged target, string    propertyName, Action action)
{
   if (target == null)
   {
       return;
   }

   if(currentContainer != null)         
       target.PropertyChanged -= currentContainer.PropertyChangedHandler;

   currentContainer = new DelegateContainer(action, propertyName);
   target.PropertyChanged += currentContainer.PropertyChangedHandler;
}

关于c# - 在静态方法(扩展方法)中取消订阅匿名事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14816777/

相关文章:

c# - 使用 Expression.AndAlso 聚合表达式列表时遇到问题

c# - Lambda 表达式和事件订阅

c# - 为什么分页的 LINQ IQueryable 性能如此差?

javascript - 异步与同步事件处理程序性能

ios - 为什么hitTest :withEvent: called three times for each touch?

c# - 扩展方法找不到类型的定义

c# - 如何在 Silverlight/C# 中访问 ListBox 控件的 ScrollViewer 元素?

c# - 林克扩展。更改源列表中的属性值

c# - 扩展方法解析

javascript - 如何检测(所有)鼠标点击?