Порядок выполнения обработчика событий - PullRequest
79 голосов
/ 29 октября 2009

Если я настрою несколько обработчиков событий, например:

_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;

в каком порядке запускаются обработчики при возникновении события RetrieveDataCompleted? Они запускаются в том же потоке и последовательно в том порядке, в котором они зарегистрированы?

Ответы [ 8 ]

115 голосов
/ 29 октября 2009

В настоящее время они выполняются в порядке их регистрации. Однако это деталь реализации, и я бы не стал полагать, что это поведение останется таким же в будущих версиях, поскольку это не требуется спецификациями.

48 голосов
/ 29 октября 2009

Список вызовов делегата упорядоченный набор делегатов, в котором каждый элемент списка вызывает точно один из методов, вызываемых делегат. Список вызовов может содержать дубликаты методов. Во время вызов, делегат вызывает методы в том порядке, в котором они появляются в список вызовов .

Отсюда: Класс делегата

9 голосов
/ 06 ноября 2013

Вы можете изменить порядок, отсоединив все обработчики, а затем снова прикрепив их в нужном порядке.

public event EventHandler event1;

public void ChangeHandlersOrdering()
{
    if (event1 != null)
    {
        List<EventHandler> invocationList = event1.GetInvocationList()
                                                  .OfType<EventHandler>()
                                                  .ToList();

        foreach (var handler in invocationList)
        {
            event1 -= handler;
        }

        //Change ordering now, for example in reverese order as follows
        for (int i = invocationList.Count - 1; i >= 0; i--)
        {
            event1 += invocationList[i];
        }
    }
}
8 голосов
/ 29 октября 2009

Порядок произвольный. Вы не можете полагаться на то, что обработчики выполняются в каком-то определенном порядке от одного вызова к другому.

Редактировать: А также - если это просто из любопытства - тот факт, что вам нужно знать, свидетельствует о серьезной проблеме проектирования.

8 голосов
/ 29 октября 2009

Они запускаются в том порядке, в котором они зарегистрированы. RetrieveDataCompleted - это многоадресных делегатов . Я просматриваю рефлектор, чтобы попытаться проверить, и похоже, что за кулисами используется массив для отслеживания всего.

2 голосов
/ 16 декабря 2015

MulticastDelegate имеет связанный список делегатов, называемый списком вызовов, состоящим из одного или нескольких элементов. Когда многоадресный делегат вызывается, делегаты в списке вызовов вызываются синхронно в порядке их появления. Если во время выполнения списка возникает ошибка, возникает исключение.

2 голосов
/ 26 февраля 2015

Если кому-то нужно сделать это в контексте System.Windows.Forms.Form, вот пример, инвертирующий порядок события Shown.

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace ConsoleApplication {
    class Program {
        static void Main() {
            Form form;

            form = createForm();
            form.ShowDialog();

            form = createForm();
            invertShownOrder(form);
            form.ShowDialog();
        }

        static Form createForm() {
            var form = new Form();
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown1"); };
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown2"); };
            return form;
        }

        static void invertShownOrder(Form form) {
            var events = typeof(Form)
                .GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(form, null) as EventHandlerList;

            var shownEventKey = typeof(Form)
                .GetField("EVENT_SHOWN", BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(form);

            var shownEventHandler = events[shownEventKey] as EventHandler;

            if (shownEventHandler != null) {
                var invocationList = shownEventHandler
                    .GetInvocationList()
                    .OfType<EventHandler>()
                    .ToList();

                foreach (var handler in invocationList) {
                    events.RemoveHandler(shownEventKey, handler);
                }

                for (int i = invocationList.Count - 1; i >= 0; i--) {
                    events.AddHandler(shownEventKey, invocationList[i]);
                }
            }
        }
    }
}
0 голосов
/ 15 декабря 2018

Во время вызова методы вызываются в том порядке, в котором они указаны в списке вызовов.

Но никто не говорит, что список вызовов поддерживает делегатов в том же порядке, в котором они добавлены. Таким образом, порядок вызова не гарантируется.

...