为什么我不能从扩展方法调用PropertyChanged事件?

时间:2011-02-07 18:43:07

标签: c# wpf extension-methods inotifypropertychanged propertychanged

我试图编写一个类来避免像“RaisePropertyChanged”这样的方法。我知道我可以从具有该实现的类继承,但在某些情况下我不能。我尝试使用扩展方法,但Visual Studio抱怨。

public static class Extension
{
    public static void RaisePropertyChanged(this INotifyPropertyChanged predicate, string propertyName)
    {
        if (predicate.PropertyChanged != null)
        {
            predicate.PropertyChanged(propertyName, new PropertyChangedEventArgs(propertyName));
        }
    }
}

它说:

  

“活动   ' System.ComponentModel.INotifyPropertyChanged.PropertyChanged'可以   仅出现在+ =或 - =

的左侧

4 个答案:

答案 0 :(得分:19)

Reed是对的。但是,我知道你要做的是什么(让你的代码可以重复使用 - 对你有益);我只想指出,通过接受PropertyChangedEventHandler 委托本身并在INotifyPropertyChanged实施中传递它,通常可以轻松解决这个问题:

public static void Raise(this PropertyChangedEventHandler handler, object sender, string propertyName)
{
    if (handler != null)
    {
        handler(sender, new PropertyChangedEventArgs(propertyName));
    }
}

然后在你的类中实现INotifyPropertyChanged,你可以像这样调用这个扩展方法:

PropertyChanged.Raise(this, "MyProperty");

这是有效的,因为as Marc said在类中声明了事件,你可以像字段一样访问它(这意味着你可以将它作为委托参数传递给方法,包括扩展名方法)。

答案 1 :(得分:11)

您只能从定义它的类中引发事件。

这一行:

predicate.PropertyChanged(propertyName, new PropertyChangedEventArgs(propertyName));

将失败,因为predicate不是定义此扩展方法的类。

这部分原因通常是通过基类而不是使用Extension方法处理的。

答案 2 :(得分:4)

事件实际上只是一个带有添加/删除的API(技术上, 是CLI中提供的可选“调用”,但c#编译器不提供它。)

你所拥有的是一场类似田野的活动;类似字段的事件充当来自外部声明类型的添加/删除API,并且仅作为内部声明类型的字段,并且仅当它是时必要的作为委托 - 最常见的是:调用订阅者(这是c#4中的一个微妙变化;在c#4 所有访问内部之前) type对该字段起作用,包括+ = / - =)。

根据定义的扩展方法不能在声明类型中 - 只有顶级(非嵌套)静态类可以提供扩展方法;所以没有任何扩展方法永远可以直接调用类似字段的事件。

答案 3 :(得分:2)

当您使用event关键字定义事件时,C#编译器实际上会在幕后为您生成许多内容。

event EventHandler MyEvent;

翻译成类似的东西(虽然不完全是因为它实际上增加了一些锁定和其他检查)......

private EventHandler _myEvent;

public EventHandler MyEvent
{
  add( EventHandler handler )
  { 
    _myEvent += handler;
  }
  remove( EventHandler handler )
  {
    _myEvent -= handler;
  }
}

正如您所看到的,实际的EventHandler _myEvent是私有的,无法直接调用。