Если я настрою несколько обработчиков событий, например:
_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;
в каком порядке запускаются обработчики при запуске события RetrieveDataCompleted
? Выполняются ли они в одном потоке и последовательно в том порядке, в котором они зарегистрированы?
c#
asynchronous
event-handling
Филип Нган
источник
источник
Ответы:
В настоящее время они выполняются в том порядке, в котором они зарегистрированы. Однако это деталь реализации, и я бы не стал полагаться на то, что это поведение останется неизменным в будущих версиях, поскольку это не требуется спецификациями.
источник
Отсюда: класс делегата
источник
add
иremove
ключевые слова события не обязательно может быть реализована в виде многостраничного литой делегата в.Вы можете изменить порядок, отсоединив все обработчики, а затем снова подключив их в желаемом порядке.
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]; } } }
источник
Порядок произвольный. Вы не можете полагаться на то, что обработчики выполняются в каком-либо определенном порядке от одного вызова к другому.
Изменить: А также - если это не просто из любопытства - тот факт, что вам нужно знать, указывает на серьезную проблему дизайна.
источник
Они запускаются в том порядке, в котором они зарегистрированы.
RetrieveDataCompleted
является многоадресным делегатом . Я просматриваю отражатель, чтобы попытаться проверить, и похоже, что за кулисами используется массив, чтобы отслеживать все.источник
Если кому-то нужно сделать это в контексте 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]); } } } } }
источник
MulticastDelegate имеет связанный список делегатов, называемый списком вызовов, состоящий из одного или нескольких элементов. Когда вызывается многоадресный делегат, делегаты в списке вызовов вызываются синхронно в том порядке, в котором они появляются. Если во время выполнения списка возникает ошибка, генерируется исключение.
источник
Но никто не говорит, что список вызовов поддерживает делегатов в том же порядке, в котором они добавляются. Таким образом, порядок вызова не гарантируется.
источник
Это функция, которая поместит новую функцию обработчика событий в любое место в списке вызовов множественного делегата.
private void addDelegateAt(ref YourDelegate initial, YourDelegate newHandler, int position) { Delegate[] subscribers = initial.GetInvocationList(); Delegate[] newSubscriptions = new Delegate[subscribers.Length + 1]; for (int i = 0; i < newSubscriptions.Length; i++) { if (i < position) newSubscriptions[i] = subscribers[i]; else if (i==position) newSubscriptions[i] = (YourDelegate)newHandler; else if (i > position) newSubscriptions[i] = subscribers[i-1]; } initial = (YourDelegate)Delegate.Combine(newSubscriptions); }
Затем вы всегда можете удалить функцию с помощью '- =' в любом удобном месте вашего кода.
PS - Я не занимаюсь обработкой ошибок для параметра «позиция».
источник
У меня была аналогичная проблема. В моем случае это было исправлено очень легко. Я никогда не видел делегата, который не использовал бы оператор + =. Моя проблема была исправлена тем, что один делегат всегда добавлялся в конце, а все остальные всегда добавлялись в начале. Пример OP будет примерно таким:
В первом случае ProcessData1 будет вызываться последним. Во втором случае сначала будет вызываться ProcessData2.
источник