Эффективный список вызовов с рекурсией и изменениями во время обработки событий - PullRequest
0 голосов
/ 28 октября 2018

Я пытаюсь реализовать эффективный список вызовов с рекурсией и изменениями во время обработки событий.

Я знаю, что мог бы использовать делегат и операторы +=, -=.Я пробую альтернативный подход и хотел бы увидеть, как он сравнивается с этим.Меня не волнует многопоточность (с использованием Unity3d).

Основные проблемы:

  1. Производительность
  2. Нет выделений
  3. Использование памяти

Является ли этот код правильным, учитывая, что единственными вызванными методами были бы конструкторы, Subscribe, Unsubscribe и Send?

Идеяза ним:

  • Вызывать только обработчики, присутствующие в списке во время вызова, используя локальную 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);
        }
    }
}
...