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

时间:2021-02-03 00:00:28

I've tried to code a class to avoid a method like "RaisePropertyChanged". I know that I can inherit from a class that has that implementation but in some cases I can't. I've tried with a Extension Method but Visual Studio complain.

我尝试编写一个类以避免类似“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));
        }
    }
}

It said:

它说:

"The event 'System.ComponentModel.INotifyPropertyChanged.PropertyChanged' can only appear on the left hand side of += or -="

“事件”System.ComponentModel.INotifyPropertyChanged。PropertyChanged'只能出现在+=或-=的左边"

4 个解决方案

#1


19  

Reed is right. However, I see what you're trying to do (make your code reusable—good for you); and I'll just point out that this is often easily rectified by accepting the PropertyChangedEventHandler delegate itself and passing it from within the INotifyPropertyChanged implementation:

芦苇是正确的。但是,我看到您正在尝试做什么(使您的代码可重用—对您有好处);我要指出的是,通过接受PropertyChangedEventHandler委托并从INotifyPropertyChanged实现中传递它,这通常很容易纠正:

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

Then from within your class which implements INotifyPropertyChanged, you can call this extension method like so:

然后从实现INotifyPropertyChanged的类内部调用这个扩展方法,如下所示:

PropertyChanged.Raise(this, "MyProperty");

This works because, as Marc said, within the class declaring the event you can access it like a field (which means you can pass it as a delegate argument to a method, including extension methods).

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

#2


10  

You can only raise an event from within the class in which it's defined.

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

This line:

这条线:

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

Will fail, since predicate is not the class which defines this extension method.

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

This is partly why this is typically handled via a base class instead of via using Extension methods.

这就是为什么这通常是通过基类而不是通过扩展方法来处理的。

#3


4  

Events are really just an API with add/remove (technically there is an optional "invoke" available in the CLI, but the c# compiler doesn't provide it).

事件实际上只是一个带有add/remove的API(严格地说,CLI中有一个可选的“调用”,但是c#编译器没有提供)。

What you have there is a field-like event; field-like events act as the add/remove API from outside the declaring type, and act like the field only inside the declaring type, and only when it is necessary to treat as a delegate - most commonly: invoking the subscribers (this is a subtle change here in c# 4; before c# 4 all access from inside the type acts against the field, including +=/-=).

你所拥有的是一个类似于场的事件;类字段事件在声明类型之外充当add/remove API,并且只在声明类型内部充当字段,并且只在需要将其作为委托处理时—最常见的是:调用订阅者(在c# 4中这是一个微妙的变化);在c# 4之前,类型内部的所有访问都对字段起作用,包括+=/-=)。

An extension method by definition cannot be inside the declaring type - only top-level (non-nested) static classes can provide extension methods; so no extension method can ever have the direct ability to invoke a field-like event.

根据定义,扩展方法不能位于声明类型的内部——只有*(非嵌套)静态类才能提供扩展方法;因此,任何扩展方法都不能直接调用类字段事件。

#4


2  

When you define an event with the event keyword, the C# compiler actually generates a number of things for you behind the scenes.

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

event EventHandler MyEvent;

Translates to something like (though not exactly as it actually adds some locking and other checks)...

翻译成这样的东西(虽然不完全像它实际添加了一些锁和其他检查)……

private EventHandler _myEvent;

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

As you can see the actual EventHandler _myEvent is private and cannot be invoked directly.

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

#1


19  

Reed is right. However, I see what you're trying to do (make your code reusable—good for you); and I'll just point out that this is often easily rectified by accepting the PropertyChangedEventHandler delegate itself and passing it from within the INotifyPropertyChanged implementation:

芦苇是正确的。但是,我看到您正在尝试做什么(使您的代码可重用—对您有好处);我要指出的是,通过接受PropertyChangedEventHandler委托并从INotifyPropertyChanged实现中传递它,这通常很容易纠正:

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

Then from within your class which implements INotifyPropertyChanged, you can call this extension method like so:

然后从实现INotifyPropertyChanged的类内部调用这个扩展方法,如下所示:

PropertyChanged.Raise(this, "MyProperty");

This works because, as Marc said, within the class declaring the event you can access it like a field (which means you can pass it as a delegate argument to a method, including extension methods).

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

#2


10  

You can only raise an event from within the class in which it's defined.

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

This line:

这条线:

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

Will fail, since predicate is not the class which defines this extension method.

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

This is partly why this is typically handled via a base class instead of via using Extension methods.

这就是为什么这通常是通过基类而不是通过扩展方法来处理的。

#3


4  

Events are really just an API with add/remove (technically there is an optional "invoke" available in the CLI, but the c# compiler doesn't provide it).

事件实际上只是一个带有add/remove的API(严格地说,CLI中有一个可选的“调用”,但是c#编译器没有提供)。

What you have there is a field-like event; field-like events act as the add/remove API from outside the declaring type, and act like the field only inside the declaring type, and only when it is necessary to treat as a delegate - most commonly: invoking the subscribers (this is a subtle change here in c# 4; before c# 4 all access from inside the type acts against the field, including +=/-=).

你所拥有的是一个类似于场的事件;类字段事件在声明类型之外充当add/remove API,并且只在声明类型内部充当字段,并且只在需要将其作为委托处理时—最常见的是:调用订阅者(在c# 4中这是一个微妙的变化);在c# 4之前,类型内部的所有访问都对字段起作用,包括+=/-=)。

An extension method by definition cannot be inside the declaring type - only top-level (non-nested) static classes can provide extension methods; so no extension method can ever have the direct ability to invoke a field-like event.

根据定义,扩展方法不能位于声明类型的内部——只有*(非嵌套)静态类才能提供扩展方法;因此,任何扩展方法都不能直接调用类字段事件。

#4


2  

When you define an event with the event keyword, the C# compiler actually generates a number of things for you behind the scenes.

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

event EventHandler MyEvent;

Translates to something like (though not exactly as it actually adds some locking and other checks)...

翻译成这样的东西(虽然不完全像它实际添加了一些锁和其他检查)……

private EventHandler _myEvent;

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

As you can see the actual EventHandler _myEvent is private and cannot be invoked directly.

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