Когда точно выполняются события на С#?

Я разработал приложение С#, которое активно использует события. Теперь это приложение иногда делает забавные вещи, которые я не могу понять или отслеживать по определенной причине, почему они должны произойти. Я считаю, что причиной этих прерывистых сбоев является какое-то concurrency или состояние гонки, которое я не ожидал.

Как точно обрабатываются события на С#? Если событие поднято, будет ли (а) часть кода, прикрепленная к этому событию, немедленно выполнить? Или событие (б) будет помещено в стек событий и будет выполняться всякий раз, когда .NET считает, что он подходит для выполнения, пока выполняется другой код?

Ответ 1

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

Хорошо, да и нет. События - это многоадресные делегаты, поэтому может быть ноль, одна или несколько "частей кода", связанных с событием. В сценарии, где их много, очевидно, один из них должен идти первым, и один из них должен пройти второй. Тот, который идет вторым, не выполняется сразу после поднятого события; он выполняется сразу после завершения первого обработчика событий.

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

Предположим, что ваше приложение плохо написано и висит в пользовательском интерфейсе. Пока пользовательский интерфейс висит, пользователь нажимает кнопку 1 и кнопку 2. Поскольку приложение висит, ничего не происходит. События для нажатия кнопки 1 и кнопки 2 не срабатывают. Но Windows создала очередь сообщений и указала на нее тот факт, что кнопка 1 и кнопка 2 имеют ожидающие клики, которые необходимо обработать, когда приложение распадается. Когда цикл сообщения перекачивается, срабатывает кнопка "1 щелчок". Когда все будет сделано, цикл сообщения снова перекачивается, и кнопка "click click click" запускается.

Итак, да, в этом случае события помещаются в очередь и выполняются позже, но это не "когда .NET считает это подходящим"; когда поток, который обрабатывает очередь сообщений, снова обрабатывает очередь сообщений. Там нет таинственной политики Windows, контролирующей ваш код.

Ответ 2

Это полностью зависит от кода повышения (и подписки) события.

Если вы поднимаете событие следующим образом:

EventHandler handler = MyEvent;

if (handler != null)
{
    handler(this, EventArgs.Empty);
}

или что-то подобное, тогда все обработчики событий будут выполнены немедленно. Это типичная реализация... вам нужно работать немного сложнее, чтобы добавить делегат каждого события в очередь сообщений WinForms или что-то в этом роде.

Если вы могли бы предоставить нам больше информации о том, какие события вы говорите и как они реализованы, мы можем помочь вам больше.

Для получения дополнительной информации о событиях и делегатах (и о различии между ними) вы можете прочитать мою статью по теме.

Ответ 3

События С#, как и остальные делегаты, выполняются сразу же при срабатывании.

Ответ 4

Если явно не реализовано иначе, события называются синхронно.

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

public event EventHandler MyEvent;

protected virtual void OnMyEvent()
{
    EventHandler handler = MyEvent; // keep a copy to avoid race conditions
    if (handler != null)
        handler(this, EventArgs.Empty);
}

Как вы можете видеть из этого кода, обработчики событий вызываются немедленно и синхронно из метода OnMyEvent.

Ответ 5

Я верю, что на ваш вопрос был дан ответ:

Обработаны ли обработчики событий асинхронно?

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

Ответ 6

Как указано в предыдущем тэссе, он полностью зависит от кода, который поднимает событие или обрабатывает событие.

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

Если вам нужны хорошие примеры/материалы о том, как события могут быть правильно обработаны на С#, вы можете взглянуть на эту статью: http://www.codeproject.com/KB/cs/event_fundamentals.aspx