在任何人订阅之前提出一个事件

时间:2017-01-01 07:43:05

标签: c#

我想提出一个事件并通知现有订阅者(如果存在)。但我也希望新订阅者能够在订阅后立即通知他们所提出的所有事件。这是开箱即用还是我需要自己实现这个功能?现在我的代码看起来像这样:

public delegate void GridCompiled(int gridsize);
public event GridCompiled OnGridCompiled;

ctor(){
    if (OnGridCompiled != null)
        OnGridCompiled(gridsize);
}

如果活动有0个订阅者,则不会被提出,并且在活动被提出后订阅的订阅者也不会被提出。

如果我需要自己实施,我的选择是什么?

1 个答案:

答案 0 :(得分:5)

没有跟踪引发事件,因此您必须自己实现这些功能。您需要一个列表来按顺序存储您之前的事件参数,并在添加新事件侦听器时执行相关事件:

class Example {
    private readonly List<GridCompiledEventArgs> m_previousEventArgs = new List<EventArgs>();
    private EventHandler<GridCompiledEventArgs> m_gridCompiled;

    public event EventHandler<GridCompiledEventArgs> GridCompiled {
        add {
            //Raise previous events for the caller
            foreach(GridCompiledEventArgs e in m_previousEventArgs) {
                value(this, e);
            }
            //Add the event handler
            m_gridCompiled += value;
        }
        remove {
            m_gridCompiled -= value;
        }
    }

    protected virtual void OnGridCompiled(GridCompiledEventArgs e) {
        if (m_gridCompiled != null) {
            m_gridCompiled(this, e);
        }
        m_previousEventArgs.Add(e);
    }
}

您已为此解决方案考虑了两件事。如果您想要解决这些问题,您的解决方案将变得更加复杂:

  1. 如果事件处理程序可以更改GridCompiledEventArgs(例如,将状态返回给调用者),则事件args将与这些更改一起存储在上一个事件列表中。此外,如果事件处理程序保留对事件args的引用,它们甚至可能在以后更改它。如果您不想这样,则必须在m_previousEventArgs中存储副本并在发起“历史性”事件之前创建另一个副本。
  2. 最佳做法是允许派生类覆盖OnGridCompiled方法,而不是处理事件或更改其行为。如果派生类更改OnGridCompiled以拦截事件而在某些情况下不提升它,则此行为将不会始终适用于“历史”事件,因为它是在没有OnGridCompiled的情况下引发的(可能只是你想要的行为)。如果要更改,则必须实施通过OnGridCompiled的解决方案。如果这是您的选项,则可以通过制作课程sealedOnGridCompiled方法private而非protected virtual来避免此问题。