Должен ли мой класс подписываться на собственные публичные события?

Я использую 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 из-за меньших накладных расходов, меньшего риска неправильного поведения со стороны наследников, и в целом это имеет больше смысла для меня. Спасибо еще раз!

10
задан Jon Comtois 18 August 2010 в 11:59
поделиться

4 ответа

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

2
ответ дан 4 December 2019 в 03:15
поделиться

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

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

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

Вариант 3 действительно кажется мне приятным «легким прикосновением».

1
ответ дан 4 December 2019 в 03:15
поделиться

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

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

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

2
ответ дан 4 December 2019 в 03:15
поделиться

If you own the state of your own object, catching events just sounds wrong to me. I would go with a separate virtual method. Don't interfere with your event and hope the children throw it. Maybe this would look something like:

    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
ответ дан 4 December 2019 в 03:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: