在事件处理期间进行递归和修改的高效调用列表

时间:2018-10-28 09:06:30

标签: c# list events delegates invocation

我正在尝试在事件处理过程中通过递归和修改来实现高效的调用列表。

我知道我可以使用委托和运算符+=-=。我正在尝试一种替代方法,希望了解它与之比较。我不在乎多线程(使用Unity3d)。

主要问题:

  1. 性能
  2. 没有分配
  3. 内存使用量

考虑到唯一调用的方法是构造函数SubscribeUnsubscribeSend,此代码正确吗?

其背后的想法:

  • 使用局部count变量仅调用在调用时列表中存在的处理程序
  • 与其删除处理程序,不如将其替换为空处理程序
  • 完成所有处理(包括递归)后清理空处理程序

using System;
using System.Collections.Generic;

/// <summary>
/// Invocation list which efficiently handles recursion and subscription/unsubscription during event handling.
/// </summary>
public class InvocationList<T> : List<Action<T>>
{
    enum State { None, Running, RunningDirty }

    static readonly Action<T> m_emptyAction = x => { };

    State m_state = State.None;

    public InvocationList()
    {
    }

    public InvocationList(int capacity)
        : base(capacity)
    {
    }    

    public void Subscribe(Action<T> handler)
    {
        Add(handler);
    }

    public bool Unsubscribe(Action<T> handler)
    {
        if (m_state == State.None)
        {
            // Not sending event, just remove handler
            return Remove(handler);
        }
        else
        {
            // Sending event, replace handler by empty action
            int index = IndexOf(handler);
            if (index >= 0)
            {
                this[index] = m_emptyAction;
                m_state = State.RunningDirty;
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    /// <summary>
    /// Raises the event. Handles recursion and subscription/unsubscription during event handling.
    /// Event is sent only to handlers present in invocation list at the moment of call.
    /// </summary>
    public void Send(T value)
    {
        if (m_state == State.None)
        {
            // Non-recursive invocation
            try
            {
                m_state = State.Running;
                ProcessHandlers(value);
            }
            finally
            {
                if (m_state == State.RunningDirty)
                {
                    // Clean up empty handlers
                    RemoveAll(s => s == m_emptyAction);
                }
                m_state = State.None;
            }
        }
        else
        {
            // Recursive invocation
            ProcessHandlers(value);
        }
    }

    private void ProcessHandlers(T value)
    {
        // Store count, this ignores handlers added during execution
        int count = Count;
        for (int i = 0; i < count; i++)
        {
            this[i](value);
        }
    }
}

0 个答案:

没有答案
相关问题