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

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

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

event EventHandler foo;

foo += One;
foo += Two;

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

Edit:
Вы должны, конечно, не полагаться на это, я просто думал. Идея заключалась в том, что делегаты многоадресной передачи аналогичны шаблону COMMAND. Так что мне просто интересно. Усушно вы использовали коллекцию, которая хранит порядок для COMMANDs, чтобы вы могли делать отменить/повторить/что угодно.

Ответ 1

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

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

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

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);
}

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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