2010-06-24 3 views
9

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

Я создал метод расширения, который перехватывает исключения:

public static void Raise(this EventHandler eh, object sender, EventArgs e) 
{ 
    if (eh == null) 
    return; 
    try 
    { 
    eh(sender, e); 
    } 
    catch { } 
} 

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

Кроме того, мне действительно неудобно просто игнорировать исключение здесь (и ни FxCop/Resharper ни на что); реалистично, что должно произойти с исключением в этом случае?

+1

Я часто задавался вопросом, как лучше всего справиться с этим. – ChaosPandion

+0

На самом деле возникает другой вопрос, который я задам отдельно; в этом вопросе я кодирую с точки зрения класса, поднимающего событие, но мне интересно, разрешено ли обработчикам событий бросать исключения в первую очередь. http://stackoverflow.com/questions/3114543/should-event-handlers-in-c-ever-raise-exceptions – Flynn1179

ответ

2

Что делать, если вы сделали что-то подобное?

public static void Raise(this EventHandler eh, object sender, EventArgs e) 
{ 
    if (eh == null) 
     return; 

    foreach(var handler in eh.GetInvocationList().Cast<EventHandler>()) 
    { 
     try 
     { 
      handler(sender, e); 
     } 
     catch { } 
    } 
} 
+0

Фактически, я сделал 'foreach (обработчик делегирования в обработчике WeaponChanged.GetInvocationList()) (отправитель, e);', но, к сожалению, 'handler (sender, e)' дает ошибку в VS, что 'метод, делегировать или событие «ожидается» для «обработчика»; Я почесываю голову над этим, это явно делегат. – Flynn1179

+0

@ Flynn1179 - Делегат сам по себе не может быть вызван в этом вопросе. Вам нужно либо выполнить, как вы видите в моем примере, или вызвать делегата следующим образом: 'handler.DynamicInvoke (sender, e);' – ChaosPandion

+0

aah .. Я запутался между делегатом и делегатом :) – Flynn1179

3

Вы должны использовать только те исключения, которые вы можете использовать. Например, вы можете получить доступ к файлу и не иметь достаточных привилегий. Если вы знаете, что это может произойти изредка, и все, что должно произойти, - это то, что дело регистрируется, а затем ловушка , только это исключение.

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

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

3

Если обработчик события не обнаружил исключения, я не вижу никакого хорошего способа обработать исключение в классе, бросающем событие. У вас нет контекста, чтобы знать, что делает обработчик. В этом случае безопаснее всего вредить приложению, так как вы не представляете, какие побочные эффекты могут вызвать другие обработчики событий, которые могут дестабилизировать ваше приложение. Урок здесь заключается в том, что обработчики событий должны быть надежными (обрабатывать собственные исключения), поскольку классы, которые запускают события, никогда не должны ловить исключения, брошенные обработчиками.

+0

Неудача быстро отличная, когда вы отлаживаете, но не так много, когда вы являетесь пользователем. Почему багги-заглушка разбивает каждое приложение, которое оно затрагивает? – Gabe

+0

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

+1

@Gabe - Багги-подключаемый модуль должен разбивать каждое приложение, которое он затрагивает, потому что это глючный плагин. Люди должны быть осведомлены о том, что это багги, поэтому его можно устранить или избежать. Защита отвратительных плагинов при возможном расходовании данных пользователя - плохая политика. –

2

Простое, но важное правило:

Каждый дефект в коде должны быть летальным, насколько это возможно уже в возможно.

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

+0

Все говорят об этом, но это не всегда так просто. Что делать, если у них нет контроля над тем, кто подписывается на мероприятие? Что делать, если необходимо продолжать обработку? – ChaosPandion

+1

@Chaos, в этом случае вам нужно структурировать свои события таким образом, чтобы это позволяло изолировать. Например, настройте модель клиент-сервер с изолированными процессами. Теперь клиент может сбой, и сервер может с радостью продолжать обработку, даже если клиенты не работают. Если у вас есть простые события обратного вызова без границ изоляции, тогда нет защиты от неуправляемого клиента, мешающего вашей обработке. Процесс не может гарантировать его императив (продолжать обработку _корректно), и безответственно, чтобы процесс мог притворяться, что он может. –

+0

Дэн: Предполагая, что это все управляемый код, как бы вы ожидали, что глючный обработчик исключений будет вмешиваться в основной процесс? – Gabe

Смежные вопросы