Почему исключения распространяются из обработчика событий? - PullRequest
4 голосов
/ 21 июля 2009

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

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

Ответы [ 6 ]

16 голосов
/ 21 июля 2009

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

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

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

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

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

2 голосов
/ 26 августа 2009

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

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

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

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

1 голос
/ 21 июля 2009

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

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

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

0 голосов
/ 23 июля 2013

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

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

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

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

0 голосов
/ 21 июля 2009

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

0 голосов
/ 21 июля 2009

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

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