18

我试图编写一个类来避免像“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

4 回答 4

20

里德是对的。但是,我知道您正在尝试做什么(让您的代码可重用——<strong>对您有好处);我只想指出,这通常很容易通过接受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");

这是因为,正如 Marc 所说,在声明事件的类中,您可以像访问字段一样访问它(这意味着您可以将其作为委托参数传递给方法,包括扩展方法)。

于 2011-02-07T18:48:25.493 回答
11

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

这一行:

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

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

这就是为什么这通常是通过基类而不是通过使用扩展方法来处理的部分原因。

于 2011-02-07T18:45:43.507 回答
4

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

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

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

于 2011-02-07T18:49:06.227 回答
2

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

event EventHandler MyEvent;

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

private EventHandler _myEvent;

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

如您所见,实际的 EventHandler_myEvent是私有的,不能直接调用。

于 2011-02-07T18:49:44.927 回答