Выполняются ли обработчики событий в порядке их присоединения к событию? Если нет, могу ли я применить какой-то порядок к обработчикам событий, чтобы они вызывались в определенном порядке?
Как я могу управлять порядком, в котором запускаются обработчики событий?
Ответ 1
Предполагая простую реализацию события (используя + = и - = в поле делегата, который, в свою очередь, будет использовать Delegate.Combine/Remove
), тогда да, обработчики событий будут вызваны в том порядке, в котором они подписаны. Гарантия действительно приведена в документации Delegate.Combine
:
Возвращаемое значение
Новый многоадресный (комбинируемый) делегат с списком вызовов, который объединяет списки вызовов и b в этом порядке.
См. статью о событиях для некоторых примеров того, что Delegate.Combine/Remove
делать (и какие события похожи на обложки).
Ответ 2
Do НЕ полагаться на упорядочение событий. Все диспетчеризации событий должны быть логически независимыми, как если бы они происходили параллельно.
Добавление обработчиков событий в других классах и потоках может нарушить предполагаемое упорядочение, это просто не безопасное предположение, и оно противоречит концепции событий как самостоятельных развязанных действий.
Я сделаю еще один шаг и утвержу, что если вы должны принять заказ на стрельбу по событиям, у вас есть серьезный дефект дизайна и/или злоупотребляют событиями.
Ответ 3
У вас может быть один обработчик событий, который вызывает другие функции или делегаты в указанном порядке.
Ответ 4
Я бы рекомендовал "обернуть его".
Сделайте что-нибудь подобное...
MyObject.MyEvent += new MyEventHandler(Wrapper);
public void Wrapper()
{
Method1();
Method3();
Method2();
}
Таким образом, вы все еще подключаете событие, но имеете полный контроль над тем, что называется.
Ответ 5
Извините за поздний ответ.
Я столкнулся с ситуацией, когда мне приходится иметь дело с порядком обработчиков событий.
У меня есть форма, и когда я нажимаю кнопку в форме, объект добавляется в коллекцию где-то в моем коде.
В коллекции есть событие "Добавлено", и к нему подключены два делегата. Один из методов удаляет любой элемент, только что добавленный в коллекцию, в то время как другой показывает сообщение пользователю.
Если у меня есть некоторые примеры кода, при срабатывании события генерируется исключение "IndexOutOfRange":
// this methods hooks two delegates to MyCollection.Added event, but the order results in a "IndexOutOfRange" exception after the event is triggered
HookEvents()
{
MyCollection.Added += new CollectionItemAddedHandler(DeleteItem_After_CollectionItemAdded);
MyCollection.Added += new CollectionItemAddedHandler(ShowMessage_After_CollectionItemAdded);
}
// when user click a button on form, add a object to MyCollection
Button_Clicked()
{
MyCollection.Add(new object());
}
// at the moment a object is added into the collection, this method remove it
DeleteItem_After_CollectionItemAdded(NewIndexArgs e)
{
MyCollection.Remove(e.NewIndex); // e.NewIndex represents the newly added item index in current collection
}
// at the moment a object is added into the collection, this method show its information (hey, but remember, I just remove it in the previous method)
ShowMessage_After_CollectionItemAdded(NewIndexArgs e)
{
MessageBox.Show(MyCollection[e.NewIndex]); // tell user what is just added into the current collection
// a "IndexOutOfRange" exception is thrown here....
}
Что будет делать этот сценарий правильно, так это то, что метод ShowMessage_After_CollectionItemAdded должен запускаться сначала, а затем это будет метод DeleteItem_After_CollectionAdded.
Хотя сначала мы можем + = метод ShowMessage..., иногда мы не можем предопределять эту последовательность до времени выполнения.