MulticastDelegate.GetInvocationList() выделяет. Это можно обойти?

Можно ли вызвать MulticastDelegate и обработать возвращаемое значение каждого подключенного обработчика без выделения памяти?

Фон

В схеме нормальных вещей Delegate[] выделено MulticastDelegate.GetInvocationList() незначительно. Однако в некоторых случаях важно минимизировать распределение. Например, во время игры в играх для Xbox, работающих на компактной платформе, каждый выделенный 1 МБ вызовет сбор и неприятную заминку частоты кадров.

После использования CLR Profiler для выявления и устранения большинства выделений во время игры у меня остается 50% мусора, вызванного вызовами обратного вызова Farseer Physics. Необходимо перебрать полный список вызовов, так как пользователь может вернуть false отменить ответ о столкновении от любого из подключенных обработчиков (и вызвать делегат без использования GetInvocationList() просто возвращает результат последнего присоединенного обработчика).

Для справки вот код Farseer, о котором идет речь:

// Report the collision to both participants. Track which ones returned true so we can
// later call OnSeparation if the contact is disabled for a different reason.
if (FixtureA.OnCollision != null)
    foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
        enabledA = handler(FixtureA, FixtureB, this) && enabledA;

1 ответ

Я нашел для себя решение в виде замены a на aList<Delegate>.

мне нужно было позвонитьGetInvocationList()на несколько кадров каждый кадрMulticastDelegate.

      private Action[] _actions;

public event Action ActionsEvent
{
    add
    {
        if (_actions == null)
            _actions = new Action[] { value };
        else
        {
            int lastIndex = _actions.Length;

            Array.Resize(ref _actions, _actions.Length + 1);

            _actions[lastIndex] = value;
        }
    }
    remove
    {
        if (_actions == null)
            return;

        int index = Array.IndexOf(_actions, value);

        if (index < 0)
            return false;

        int newLength = _actions.Length - 1;

        if (newLength > 0)
        {
            Action[] newActions = new Action[newLength];

            if (index > 0)
                Array.Copy(_actions, 0, newActions, 0, index);

            if (index < newLength)
                Array.Copy(_actions, index + 1, newActions, index, newLength - index);

            _actions = newActions;
        }
        else
            _actions = null;
    }
}

Либо оптимизированная версия (но имеет существенные отличия от стандартной). Если вам нуженDelegate-подобное поведение, то используйте первый вариант.

      private List<Action> _actions;

public event Action ActionsEvent
{
    add
    {
        if (_actions == null)
            _actions = new List<Action>();

        _actions.Add(value);
    }
    remove
    {
        if (_actions != null)
        {
            _actions.Remove(value);

            if (_actions.Count == 0)
                _actions= null;
        }
    }
}
Другие вопросы по тегам