Нужно ли писать отдельный catch для каждого типа исключения в .NET
Что проверяют
Ловите ли вы исключение только тогда, когда знаете, что с ним делать. Попутно спрашивают инструменты языка: порядок блоков, фильтры when, разницу между throw и throw ex.
Как отвечать
Отдельный блок нужен там, где отличается реакция. Если на все случаи реакция одна, записать в лог и отдать ошибку наверх, хватит одного блока или вообще ни одного. Ловить ради того, чтобы «не падало», не стоит: необработанное исключение с полным стектрейсом полезнее проглоченного.
Что показать:
- блоки проверяются сверху вниз, наследника пишут раньше предка, иначе компилятор укажет на недостижимый код;
- фильтр
whenразделяет случаи по условию:catch (SqlException e) when (e.Number == 1205)поймает взаимную блокировку и пропустит остальное; - фильтр не разматывает стек, в отличие от связки «поймали, проверили, перебросили», поэтому в отладчике видно исходное место;
- проброс делается голым
throw;, формаthrow ex;затирает стектрейс; - освобождение ресурсов через
usingилиfinally, а не черезcatch; - в веб-приложении разумнее один обработчик на всё приложение, а не
tryв каждом действии контроллера.
Где спотыкаются
Объясняют выбор производительностью: мол, один блок быстрее нескольких. Количество блоков на скорость не влияет вовсе, дорого само возбуждение исключения со сбором стектрейса и раскруткой, поэтому исключения и не используют для управления потоком.
Пишут catch (Exception ex) и кладут в лог только ex.Message. Теряются тип, стек и вложенные исключения, а у AggregateException из параллельного кода сообщение вообще ни о чём не говорит, смотреть надо InnerExceptions.
Ловят то, что ловить не нужно. Штатная отмена по токену прилетает исключением и в логе превращается в поток фальшивых ошибок; отдельная история с catch (Exception) вокруг всего приложения, который прячет и ошибки конфигурации на старте.