Вызваны ли подписчики событий в порядке подписки?

Можно ли предположить, что подписчики на события называются в порядке подписки?
Пример:

void One(object sender, EventArgs e) {}
void Two(object sender, EventArgs e) {}

event EventHandler foo;

foo += One;
foo += Two;

Всегда ли One () вызывается перед Two () при возникновении события?

Редактировать:
Вы, конечно, не должны полагаться на это, я просто подумал. Идея заключалась в том, что многоадресные делегаты аналогичны шаблону COMMAND. Так что мне просто интересно. Обычно вы используете коллекцию, которая хранит порядок для КОМАНД, чтобы вы могли отменить / повторить / что угодно.

 Jon B17 дек. 2008 г., 14:37

Ответы на вопрос(5)

Решение Вопроса

Учитывая эту реализацию, да, они всегда будут вызываться в таком порядке.

Если событие на самом деле использует какой-то странный и замечательный способ обработки подписок, оно может делать разные вещи, но «нормальные» реализации будут делать правильные вещи.

Чтобы было ясно, подписка на обработчик событий просто означает вызов соответствующей части «добавить» события. Если событие обрабатывает это, делая что-то вроде:

myHandler += value;

это переводится на

myHandler = Delegate.Combine(myHandler, value);

а такжеDelegate.Combine гарантирует заказ. Однако, если у вас было такое событие:

private LinkedList<EventHandler> eventHandlers = new LinkedList<EventHandler>;

public event EventHandler Foo
{
    add
    {
        eventHandlers.AddFirst(value);
    }
    remove
    {
        // do stuff here too
    }
}

и затем запустил событие, выполнив что-то вроде:

foreach (EventHandler handler in eventHandlers)
{
    handler(this, EventArgs.Empty);
}

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

Резюме: Для всех нормальных событий, вы можете положиться на порядок. Теоретически, события могут делать то, что им нравится, но я никогда не видел события, котороене поддерживать соответствующий порядок.

 Steven A. Lowe17 дек. 2008 г., 14:43
Джон, ты знаешь лучше, чем большинство, что никогда не следует полагаться на порядок выполнения обработчиков событий; почему вы позволяете этот слайд?

Обратите очень пристальное внимание на предостережения Джона Скита - «Учитывая эту реализацию ...». Другими словами, сделайте малейшее изменение (несколько потоков, другие обработчики и т. Д.), И вы рискуете потерять неизменность порядка выполнения.

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

Я сделаю еще один шаг и утверждаю, что если вам нужно принять заказ на запуск событий, у вас есть серьезный недостаток дизайна и / или неправильное использование событий.

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

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

Быстрый ответ будет "Это не ваше дело" :)

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

Может быть, в этом случае вам не нужен подход, основанный на событиях, чтобы добиться цели?

То, что сказал Джон Скит, технически правильно для текущей реализации, но, возможно, это не так в c # 8.5 или VBasic 15.0. Опора на детали реализации всегда приносит больше вреда, чем пользы.

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

Если Two () зависит от того, что делает One (), то либо присоедините один делегат, который вызывает два метода в правильном порядке, либо вызовите Two () при необходимости One ().

 Trap18 дек. 2008 г., 11:58
Кроме того, я бы сказал, что нет такогоправильный способ информирования подписчиков.

Ваш ответ на вопрос