Как я могу управлять порядком, в котором запускаются обработчики событий?

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

Ответ 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..., иногда мы не можем предопределять эту последовательность до времени выполнения.