Должен ли мой класс подписаться на свои публичные мероприятия? - PullRequest
10 голосов
/ 17 августа 2010

Я использую C # 3.0.Следуя стандартному шаблону событий, у меня есть:

    public event EventHandler<EventArgs> SomeEventHappens;

    protected virtual void OnSomeEventHappens(EventArgs e)
    {
        if (SomeEventHappens != null)
        {
            SomeEventHappens(this, e);
        }
    }

    private object _someProperty;

    public object SomeProperty
    {
        get
        {
            return _someProperty;
        }
        private set
        {
            if (_someProperty == value)
            {
                return;
            }
            OnSomeEventHappens(EventArgs.Empty);
            _someProperty = value;
        }
    }

В моем классе Я хотел бы предпринять некоторые действия, когда SomeProperty изменится.На мой взгляд, у меня есть 3 варианта:

1) Делайте вещи в моем SomeProperty сеттере.Что-то делает мне неправильный способ сделать это, так как я пытаюсь присоединиться к философии всего, должен делать одно и делать это хорошо.Кажется, что вбивание вещей в сеттер идет против этого или, по крайней мере, имеет склонность к.

2) Делайте вещи в OnSomeEventHappens.Опять же, кажется, немного против того, чтобы держать это в простых частях.Кроме того, если этот метод будет переопределен, он может потерять функциональность, если разработчик не вызовет базовый метод.

3) Пусть класс подпишется на SomeEventHappens.Мне кажется, что это правильный выбор с точки зрения инкапсуляции, и кажется довольно чистым.Опять же, возможные последствия, если переопределено OnSomeEventHappens.

Может быть, есть что-то более элегантное?Я не могу выбрать между вариантом 2 и 3, и мне любопытно, какова наилучшая практика.Возможно, самое безопасное место в установщике свойств.

Мысли?

Обновление: Спасибо за замечательные комментарии и ответы ниже.Я узнал, что это нормально, когда класс подписывается на свои собственные события, хотя в моем случае я склонен не делать этого из-за накладных расходов.Я подумал о поведении потенциальных переопределений моих виртуальных методов и о том, что именно я хочу, чтобы произошло.

В моем случае, в действительности, я не хочу, чтобы события возникали без установки свойства,Поскольку ответы, приведенные ниже, направили мой мыслительный процесс, я думаю, что могу выбрать вариант 1 из-за меньших накладных расходов, уменьшенного риска ненадлежащего поведения со стороны наследников, и это, как правило, лучше для меня.Еще раз спасибо!

Ответы [ 4 ]

2 голосов
/ 17 августа 2010

Если вы вызываете SomeEventHappens и OnSomeEventHappens из некоторого общего местоположения (процедура свойства или другая функция), то вам не нужно беспокоиться о переопределителях, игнорирующих создание события. Я бы предпочел переопределить функцию, а не обрабатывать события, потому что там меньше накладных расходов.

2 голосов
/ 17 августа 2010

В объектных структурах за пределами .NET объект, который подписывается на свои собственные события, не одобряется в первую очередь потому, что такие вещи приводят к циклическим ссылкам, которые могут поддерживать объект в течение неопределенного времени.Это не проблема в .NET, но мне все еще кажется «странным», что объект нащупывает себя таким образом.

Если класс всегда должен знать, когда происходят изменения в свойстве, вашЛучшая ставка IMO - сделать метод OnSomeEventHappens виртуальным и переопределить его в классах-потомках, которым требуется дополнительная информация.Можно добавить код в метод запуска событий.Метод запуска событий существует именно так, чтобы у всех, кто хочет запустить это событие, был единый способ сделать это.

Если вам нужно лишь время от времени получать информацию о том, когда свойство изменяется, тогда я полагаю, что подписка и отменак событию подойдет.

1 голос
/ 17 августа 2010

Если вы владеете состоянием своего собственного объекта, ловить события для меня просто звучит неправильно. Я бы пошел с отдельным виртуальным методом. Не вмешивайся в свое мероприятие и надейся, что его бросят дети. Может быть, это будет выглядеть примерно так:

    private object _someProperty;
    public object SomeProperty
    {
        get
        {
            return _someProperty;
        }
        private set
        {
            if (_someProperty != value)
            {
              OnSettingSomeProperty(_someProperty, value);
              OnSomeEventHappens(EventArgs.Empty);
              _someProperty = value;
            }
        }
    }

    protected virtual void OnSettingSomeProperty(object oldValue, object newValue)
    {
        // children can play here, validate and throw, etc.
    }
1 голос
/ 17 августа 2010

Будете ли вы всегда хотеть предпринять это действие, или вы хотите подписаться и отказаться от подписки? В последнем случае вариант 3 явно хорошая идея.

Является ли действие, которое вы хотите совершить, видом действия, которое другой класс, возможно, пожелает предпринять? Опять же, это склоняется к варианту 3.

Является ли действие, которое вы хотите выполнить, неотъемлемой частью установки свойства? Если это так, может быть целесообразно действие 1.

Вариант 3 звучит как приятный подход "легкого прикосновения" для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...