Порядок выполнения обработчика событий
Если я настроил несколько обработчиков событий, например:
_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;
в каком порядке выполняются обработчики, когда событие RetrieveDataCompleted
уволен? Выполняются ли они в одном потоке и последовательно в порядке регистрации?
7 ответов
В настоящее время они выполняются в том порядке, в котором они зарегистрированы. Однако это деталь реализации, и я бы не стал полагаться на это поведение, оставаясь неизменным в будущих версиях, поскольку это не требуется спецификациями.
список вызовов делегата упорядоченный набор делегатов, в котором каждый элемент списка вызывает точно один из методов, вызываемых делегат. Список вызовов может содержат повторяющиеся методы. Во время призыв,делегат вызывает методы в том порядке, в каком они появляются в список вызовов.
отсюда: Класса Delegate
порядок произвольный. Нельзя полагаться на обработчики, выполняемые в определенном порядке от одного вызова к другому.
Edit: а также-если это не просто из любопытства-тот факт, что вам нужно знать, указывает на серьезные проблемы дизайна.
вы можете изменить порядок, отсоединив все обработчики, а затем повторно прикрепив в нужном порядке.
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
Это Делегаты Многоадресной Рассылки. Я смотрю через рефлектор, чтобы попытаться проверить, и похоже, что массив используется за кулисами, чтобы отслеживать все.
Если кому-то нужно сделать это в контексте системы.Окна.Формы.Form, вот пример инвертирования порядка показанного события.
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 есть связанный список делегатов, называемый списком вызовов, состоящий из одного или нескольких элементов. При вызове делегата многоадресной рассылки делегаты в списке вызовов вызываются синхронно в том порядке, в котором они появляются. Если во время выполнения списка возникает ошибка, возникает исключение.