Ловля базового класса исключений в .NET - PullRequest
19 голосов
/ 22 сентября 2008

Я продолжаю слышать, что

catch (Exception ex)

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

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

EDIT:

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

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

Ответы [ 16 ]

30 голосов
/ 22 сентября 2008

Плохая практика -

catch (Exception ex){}

и варианты:

catch (Exception ex){ return false; }

и т.д.

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

18 голосов
/ 22 сентября 2008

Я считаю аргументы в пользу того, что общие уловы всегда плохи, потому что они слишком догматичны. У них, как и у всего остального, есть место.

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

Вот мое общее правило (и, как и все правила, оно разработано, чтобы его нарушать при необходимости):

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

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

Если я не могу ничего сделать с исключением, кроме ошибки (скажем, база данных отключена), или если исключение действительно является неожиданным, перехват всех возьмет его, зарегистрирует его и быстро откажет с помощью общее сообщение об ошибке, отображаемое пользователю перед смертью. (Конечно, есть определенные классы ошибок, которые почти всегда безуспешно терпят неудачу - OutOfMemory, StackOverflow и т. Д. Мне повезло, что мне не приходилось иметь дело с ошибками в коде уровня продукта ... пока!)

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

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

11 голосов
/ 22 сентября 2008

Когда я вижу

catch (Exception ex)

моя рука начинает хвататься за молоток. Там почти нет оправданий, чтобы поймать базу Exception. Единственные действительные случаи, которые приходят мне в голову:
1) Сторонний компонент генерирует исключение (будь он проклят, его автор)
2) Обработка исключений очень высокого уровня (в крайнем случае) (например, обработка «необработанных» исключений в приложении WinForms)

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

Я бы не согласился с Армином Ронахером. Как бы вы себя вели, если бы возникла исключительная ситуация StackOverflow? Попытка выполнить дополнительные действия может привести к еще худшим последствиям. Поймать исключение, только если вы можете справиться с ним осмысленно и безопасно. Перехват System.Exception для охвата диапазона возможных исключений ужасно неверен. Даже когда вы перебрасываете его.

6 голосов
/ 22 сентября 2008

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

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

3 голосов
/ 22 сентября 2008

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

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

3 голосов
/ 22 сентября 2008

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

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

2 голосов
/ 22 сентября 2008

В качестве исключения мы используем Catch ex (вариант VB.Net). Мы регистрируем его и регулярно проверяем наши журналы. Отследить причины и устранить.

Я думаю, что Catch ex as Exception полностью приемлемо один раз вы имеете дело с рабочим кодом, и у вас есть общий способ корректно обрабатывать неизвестные исключения. Лично я не добавляю общий улов до тех пор, пока не завершу модуль / новую функциональность и не включу специализированную обработку для любых исключений, которые я обнаружил при тестировании. Кажется, это лучшее из обоих миров.

2 голосов
/ 22 сентября 2008

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

try {something} catch (SqlException) {do stuff} catch (Exception) {do other stuff}

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

Общепринятая мудрость гласит, что это правильный способ обработки исключений (и что одиночный Catch (Exception ex) плох). На практике этот подход не всегда работает, особенно когда вы работаете с компонентами и библиотеками, написанными кем-то другим.

Эти компоненты часто генерируют исключение другого типа в производственной среде, отличное от того, которое ожидал ваш код, в зависимости от поведения компонента в вашей среде разработки, даже если основная проблема одинакова в обеих средах. Это удивительно распространенная проблема в ASP.NET, и она часто заставляет меня использовать голый блок Catch (Exception ex), который не заботится о том, какой тип исключения выдается.

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

2 голосов
/ 22 сентября 2008

Это нормально, если вы повторно поднимаете исключения, с которыми не можете справиться должным образом. Если вы просто поймаете исключения, вы можете скрыть ошибки в коде, который вы не ожидаете. Если вы перехватываете исключения для их отображения (и обходите поведение die-and-print-traceback-to-stderr), это вполне приемлемо.

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

Я немного работал с исключениями, и вот структура реализации, которой я сейчас следую:

  1. Уменьшить все до Nothing / String.Empty / 0 и т. Д. Вне Try / Catch.
  2. Инициализируйте все внутри Try / Catch до желаемых значений.
  3. Сначала поймайте наиболее конкретные исключения, например, FormatException, но оставить в базе Обработка исключений как последнее средство (вы можете иметь несколько блоков catch, помните)
  4. Почти всегда бросать исключения
  5. Пусть sub Application_Error в global.asax корректно обрабатывает ошибки, например, вызвать пользовательскую функцию для записи сведений об ошибке в файл и перенаправить на страницу с ошибкой
  6. Убейте все объекты, которые вы Dim'd в блоке, наконец,

Один из примеров, когда я считал приемлемым не обрабатывать исключение «должным образом», недавно работал со строкой GUID (strGuid), переданной через HTTP GET на страницу. Я мог бы реализовать функцию проверки правильности строки GUID перед вызовом New Guid (strGuid), но это показалось довольно разумным для:

Dim myGuid As Guid = Nothing

Try
    myGuid = New Guid(strGuid)
    'Some processing here...

Catch ex As FormatException
    lblError.Text = "Invalid ID"

Catch ex As Exception 
    Throw

Finally
    If myGuid IsNot Nothing Then
        myGuid = Nothing
    End If

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