Почему я не могу вызвать событие PropertyChanged из метода расширения? - PullRequest
14 голосов
/ 07 февраля 2011

Я пытался закодировать класс, чтобы избежать использования метода типа "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 ]

20 голосов
/ 07 февраля 2011

Рид верно. Однако я вижу, что вы пытаетесь сделать (сделать ваш код многоразовым - хорошо для вас ); и я просто укажу, что это часто легко исправить, приняв сам 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");

Это работает, потому что, как сказал Марк , внутри класса, объявляющего событие, вы можете обращаться к нему как к полю (что означает, что вы можете передать его как аргумент делегата методу включая методы расширения).

11 голосов
/ 07 февраля 2011

Вы можете вызвать событие только из класса, в котором оно определено.

Эта строка:

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

Сбой, поскольку predicate не является классом, который определяет этот метод расширения.

Это отчасти потому, что это обычно обрабатывается с помощью базового класса, а не с помощью методов Extension.

4 голосов
/ 07 февраля 2011

События - это на самом деле просто API с добавлением / удалением (технически там - это необязательный «invoke», доступный в CLI, но компилятор c # не предоставляет его).

То, что у вас есть, это событие, похожее на поле;Подобные полям события действуют как API добавления / удаления из вне декларирующего типа и действуют как поле только внутри декларирующего типа и только тогда, когда это необходимо для обработки в качестве делегата - чаще всего: вызов подписчиков (это небольшое изменение здесь, в c # 4; до c # 4 все доступ из внутри , тип действует против поля, включая + = / - =).

Метод расширения по определению не может быть внутри объявленного типа - только статические классы верхнего уровня (не вложенные) могут предоставлять методы расширения;поэтому ни один метод расширения не может когда-либо иметь прямую возможность вызывать событие, подобное полю.

2 голосов
/ 07 февраля 2011

Когда вы определяете событие с помощью ключевого слова event, компилятор C # на самом деле генерирует ряд вещей для вас за кулисами.

event EventHandler MyEvent;

Переводит что-то вроде (хотя не совсем так, как на самом деле добавляет некоторые блокировки и другие проверки) ...

private EventHandler _myEvent;

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

Как видите, фактический EventHandler _myEvent является приватным и не может быть вызван напрямую.

...