我的班级应该订阅自己的公共活动吗?

时间:2010-08-17 18:49:02

标签: c# events

我正在使用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 setter中做一些事情。因为我试图订阅所有事情的理念应该做一件事并做得好,因此有些事情让我误解了这一点。将东西塞入制定者似乎与此相反,或者至少具有倾向。

2)在OnSomeEventHappens中做一些事情。再次,似乎有点反对保持这个简单的部分。此外,如果此方法被覆盖,如果实现者不调用基本方法,则可能会丢失功能。

3)让班级订阅SomeEventHappens。对我而言,就封装而言,这似乎是正确的选择,而且看起来很干净。同样,如果覆盖OnSomeEventHappens,可能会产生影响。

也许有更优雅的东西?我不能在选项2和3之间做出决定,我很好奇最佳实践是什么。也许最安全的地方就是物业安置者。

思想?

更新 感谢下面的精彩评论和答案。我已经知道让一个类订阅自己的事件是“没问题的”,尽管在我的情况下我倾向于不做因为开销。我已经考虑了我的虚拟方法的潜在重写者的行为以及我想要发生的事情。

在我的真实案例中,我真的不希望在没有设置属性的情况下引发事件。由于下面的答案指导了我的思考过程,我认为我可以选择1,因为开销较低,继承人不正当行为的风险降低,而且通常对我来说更有意义。再次感谢!

4 个答案:

答案 0 :(得分:2)

如果从某个公共位置(属性过程或其他函数)调用SomeEventHappens和OnSomeEventHappens,那么您不必担心忽略引发事件的覆盖器。我宁愿覆盖一个函数而不是处理事件,因为开销较少。

答案 1 :(得分:2)

在.NET之外的对象框架中,订阅自己的事件的对象主要是因为这样的事情导致循环引用可以使对象无限期地存活。这在.NET中不是一个问题,但对于我来说这个对象以这种方式进行摸索似乎仍然“奇怪”。

如果一个类总是需要知道属性何时发生变化,那么最好的办法是将OnSomeEventHappens方法设置为虚拟,并在需要附加信息的后代类中覆盖它。将代码放入事件触发方法中是可以的。事件发射方法正是因为每个想要发射该事件的人都有统一的方法来做这件事。

如果您偶尔需要通知房产何时发生变化,那么我认为订阅和取消订阅该活动是合适的。

答案 2 :(得分:1)

总是想要采取此行动,或者您是否想要订阅和取消订阅?在后一种情况下,选项3显然是一个好主意。

您希望采取其他类可能希望采取的种类行动吗?再次,这将倾向于选项3。

您希望采取的行动本身是设置财产的一部分吗?如果是,建议采取行动1。

选项3对我来说听起来像是一种不错的“轻触”方法。

答案 3 :(得分:1)

如果您拥有自己对象的状态,捕捉事件对我来说听起来不对。我会使用单独的虚拟方法。不要干涉你的活动,希望孩子们扔掉它。也许这看起来像:

    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.
    }