Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Красивый способ добавить событие на изменение свойства

#c_sharp


Есть класс, содержащий свойство, и событие, которое должно происходить при изменении
этого свойства:
class A
{
    public Value { get; set; }
    public event EventHandler ValueChanged;
}

Есть два других класса, которые могут это свойство изменять и должны оповещаться,
если свойство было изменено не ими. Вернее даже так: оповещаться они могут в любом
случае, но должна быть возможность узнать кто именно инициировал изменение.
Проблема в том, что в Value {set; } передаётся лишь новое значение, и узнать инициатора
уже не получится. И единственный выход, что я вижу -- это заменить Value {get; set;}
на set(newValue, initiator); get();    


Ответы

Ответ 1



Есть ещё DependencyProperty. Вроде бы считается более продвинутым механизмом, чем сущности компонентной модели .NET. Хотя тоже не совсем понятно, чем это могло бы помочь. Я бы сделал свойство только для чтения, а менял бы его значение через метод с двумя параметрами. А перед этим я бы подумал, насколько правильно спроектировано приложение. Знание о том, кто изменил свойство объекта, инициировавшего событие, противоречит идее событий как таковых. Может, Вам просто не бросать событие об изменении свойства, если фактически значение не поменялось?

Ответ 2



В C# уже есть механизм для подобного рода оповещений - INotifyPropertyChanged. Пример взаимодействия такого класса и уведомления всех подписчиков при изменения какого-либо свойства объекта: public class MyClass : INotifyPropertyChanged { private string imageFullPath; protected void OnPropertyChanged(PropertyChangedEventArgs e) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, e); } protected void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } public string ImageFullPath { get { return imageFullPath; } set { if (value != imageFullPath) { imageFullPath = value; OnPropertyChanged("ImageFullPath"); } } } public event PropertyChangedEventHandler PropertyChanged; } Также вполне возможно выполнять отдельную обработку для каких-либо конкретных свойств (ImageFullPath в случае этого примера): protected void OnImageFullPathChanged(EventArgs e) { EventHandler handler = ImageFullPathChanged; if (handler != null) handler(this, e); } public event EventHandler ImageFullPathChanged;

Ответ 3



Первый способ Вы сами описали - это действительно сделать изменение свойства через метод с двумя параметрами. Более "замороченный" способ - добавьте в событие параметр объект-инициатор, и при вызове события из сеттера пробегитесь вверх по стеку и с помощью Reflection определите класс, из которого выполняется вызов. Не знаю, то ли это, что Вам нужно, но я в некоторых местах использовал подобный подход. Плох он, в первую очередь, непредсказуемым поведением при вызове из лямбд и прочих анонимных вещей. Добиться чуть лучшего поведения можно путем установки на потенциальных инициаторов изменений (классы или методы) дополнительных атрибутов и искать по стеку класс (или метод - в зависимости от того что нужно), который выполняет вызов. P.S. про чтение стека вызовов можно почитать здесь.

Комментариев нет:

Отправить комментарий