Почему исключения распространяются из обработчика событий?

2

Рассмотрим следующую программу. Как поведение, которое он отображает (а именно, что исключения будут распространяться из обработчика событий), "хорошо"? Насколько я могу судить, это может быть только плохим; неожиданные исключения появляются из функций, которых они не должны. В моем конкретном случае он убивал нитки. Таким образом, это поведение действительно хорошо в некоторых случаях? Является ли это причиной того, что исключение исключений из обработчиков событий - плохой дизайн?

static class Program {
    static void Main()
    {
        Foo foo = new Foo();
        foo.SomeEvent += ThrowException;

        try 
        {
            foo.OnSomeEvent();
        } 
        catch (Exception) 
        {
            // This is printed out
            Console.WriteLine("Exception caught!");
        }
    }

    static void ThrowException(object sender, EventArgs e)
    {
        throw new Exception();
    }
}

// Define other methods and classes here
class Foo 
{
    public event EventHandler SomeEvent;

    public void OnSomeEvent()
    {
        SomeEvent(this, EventArgs.Empty);
    }
}
Теги:
exception
exception-handling
event-handling
events

6 ответов

14
Лучший ответ

Какая ваша предпочтительная альтернатива - молча усвоить исключение? Мне это совсем не понравится.

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

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

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

В принципе, я не думаю, что в поле CS/SE все-таки "правильная" обработка ошибок. Я даже не уверен, что есть элегантный способ делать правильные вещи, которые легко выразить во всех ситуациях... но я надеюсь, что нынешняя ситуация не так хороша, как только она становится.

  • 0
    +9000 последний абзац!
  • 0
    Вот расширение этого вопроса: можно ли ловить Exception ? Один конкретный случай, который приходит мне на ум в моем текущем проекте, - это обработка пользовательских сценариев. Предполагая, что они компилируются вообще, когда я пытаюсь их запустить, у меня есть блок try / catch (Exception) вокруг вызова метода, который они только что создали. Конечно, если возникает ошибка, она сообщается пользователю, чтобы он мог исправить свой сценарий, но действительно ли это дает сбой?
Показать ещё 4 комментария
2

Основной аспект обработки исключений, обсуждаемый здесь, заключается в следующем: не поймайте исключение, если вы не знаете, как его обрабатывать. Но позвольте говорить о шаблоне наблюдателя, где уведомитель испускает событие (или сигнал) об этом изменении состояния, и слушатели обрабатывают его. Хорошим примером уведомителя является нажатие кнопки "нажатие". Находит ли кнопка заботу о том, кто является слушателем и что они делают? На самом деле, нет. Если вы слушатель, и вы получили это событие, то у вас есть работа. И если вы не можете этого сделать, вам придется обработать эту ошибку или сообщить пользователю, потому что передача исключений на кнопку не имеет смысла - кнопка определенно не знает, как обрабатывать ошибки работы слушателя. И переключатель состояния смены состояний (возможно, какой-то цикл сообщений) тоже не работает - ваше приложение закончит с Main() сбой.

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

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

Итак, мой совет - поймать все исключения в обработчике событий, но выяснить, как их обрабатывать. Или иначе никто не будет.

1

Мои личные предубеждения заключаются в том, что не исключение исключений, как правило, плохое. Единственное "исключение" для этого правила для меня - это простые приложения, в которых непокрытое исключение обозначает процесс, вы видите ошибку и исправляете ее.

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

Беззаботное глотание исключений, как правило, плохо также, что-то плохое, что он нуждается в исправлении. Итак, возможно, зарегистрировать сообщение, а затем вернуться?

  • 0
    Правильно ли тогда ловить Exception ? то есть. на верхнем уровне потока обработки, чтобы поддерживать его после проверки работоспособности.
  • 0
    Я предпочел бы сбой, перезапустить и отправить журнал. Кроме того, некоторые исключения вы не можете поймать (OutOfMemory, StackOverflow и ThreadAbort).
Показать ещё 6 комментариев
0

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

Это означает, что если слушатель хорош и ловит его Исключения (он может сделать это для известных), вы в порядке.

Для остальных, неизвестных исключений или в речи Java "Исключения Runtime", вы должны быть готовы к ним так же, как если бы они произошли в вашем коде.

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

0

Событие - это не что иное, как синтаксический сахар вокруг вызова функции, поэтому имеет смысл, что он будет распространяться до функции, которая вызвала событие. Что, в противном случае, должно быть поведение? Исключение должно идти куда-то.

0

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

  • 0
    Re: мой последний вопрос: должен ли этот контракт всегда заключаться в том, чтобы обработчики событий не генерировали исключения (или допускали необработанные исключения), если API не говорит, что вы можете генерировать AException, BException и т. Д.?
  • 0
    Этот контракт может быть любым удобным. Если источник события находится в .NET, вполне разумно ожидать, что обработчик может генерировать любые исключения .NET.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню