Почему я не могу вызвать событие 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' может появляются только в левой части + = или - ="
Ответы
Ответ 1
Рид прав. Тем не менее, я вижу, что вы пытаетесь сделать (сделайте свой код повторно используемым полезным для вас); и я просто укажу, что это часто легко исправить, приняв сам делегат 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");
Это работает, потому что как сказал Марк, в классе, объявляющем событие, вы можете получить к нему доступ, как поле (это означает, что вы можете передать его как аргумент делегата метод, включая методы расширения).
Ответ 2
Вы можете только поднять событие из класса, в котором он определен.
Эта строка:
predicate.PropertyChanged(propertyName, new PropertyChangedEventArgs(propertyName));
Ошибка, так как predicate
не является классом, который определяет этот метод расширения.
Отчасти это объясняется тем, что это обычно обрабатывается через базовый класс вместо использования методов расширения.
Ответ 3
События - это просто API с добавлением/удалением (технически в CLI есть необязательный "вызов", но компилятор С# не предоставляет его).
У вас есть полевое событие; полевые события действуют как API добавления/удаления извне объявляющего типа и действуют как поле только внутри типа объявления, и только тогда, когда это необходимо рассматривать как делегат - чаще всего: вызывая подписчиков (это незначительное изменение здесь в С# 4, а до С# 4 весь доступ изнутри действует против поля, включая + =/- =).
Метод расширения по определению не может быть внутри класса объявления - только статические классы верхнего уровня (не вложенные) могут предоставлять методы расширения; поэтому метод расширения никогда не может иметь прямую возможность вызывать полевое событие.
Ответ 4
Когда вы определяете событие с ключевым словом event
, компилятор С# фактически генерирует для вас несколько вещей за кулисами.
event EventHandler MyEvent;
Переводит на что-то вроде (хотя не совсем так, как на самом деле добавляет некоторые блокировки и другие проверки)...
private EventHandler _myEvent;
public EventHandler MyEvent
{
add( EventHandler handler )
{
_myEvent += handler;
}
remove( EventHandler handler )
{
_myEvent -= handler;
}
}
Как вы можете видеть, фактический EventHandler _myEvent
является закрытым и не может быть вызван напрямую.