Обработка исключений
Исключение — это объект, описывающий сбой, который прерывает нормальный ход выполнения и «всплывает» вверх по стеку вызовов, пока его кто-нибудь не поймает. В C# это штатный способ сообщить об ошибке: вместо кодов возврата метод бросает исключение, а вызывающий решает, обработать его или пропустить дальше.
Вся тема держится на нескольких инвариантах, которые легко перепутать. try защищает рискованный код; из нескольких catch выполняется ровно один — первый подходящий по типу сверху вниз; finally выполняется в любом случае и потому служит местом для очистки. Поверх этого — как правильно пробросить исключение, не потеряв стек, когда завести свой тип, а когда переиспользовать встроенный, и как using превращает освобождение ресурсов в детерминированный вызов Dispose. Полная карта — в слоях ниже.
Карта темы
- Обработка исключений —
try/catch/throw, поиск обработчика по типу,throw;противthrow ex;. - Несколько catch — проверка сверху вниз, «первый подходящий побеждает», конкретное перед общим.
- Блок finally — выполняется всегда, даже после
return; когда он всё же пропускается. - Пользовательские исключения — наследование от
Exception, стандартные конструкторы, доменный контекст. - Оператор using — детерминированный
Disposeпри выходе из области, скрытый try/finally. - IDisposable — контракт освобождения ресурсов и паттерн Dispose.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Считать, что finally выполняется только при исключении | finally выполняется всегда — и при успехе, и после return |
Проброс через throw ex; | Стек вызовов сбрасывается на строку проброса — настоящий источник сбоя теряется |
Ставить catch (Exception) первым | Более конкретные блоки ниже становятся недостижимы — ошибка компиляции |
Ждать, что сработают несколько подходящих catch | Выполняется только первый совпавший обработчик, затем управление идёт в finally |
Наследовать своё исключение от ApplicationException | Класс устарел; наследуйтесь напрямую от Exception |
| Полагаться на GC для закрытия файлов и соединений | Ресурс держится до недетерминированной финализации; нужен using/Dispose |
Значение для собеседований
Обработку исключений спрашивают, чтобы отделить тех, кто пишет только «счастливый путь», от тех, кто думает о сбоях. Ответы здесь короткие, но показательные: перепутать порядок catch или сказать, что throw ex; сохраняет стек, — заметный красный флаг.
Что обычно проверяют:
- Роли
try,catch,finallyи чтоfinallyвыполняется всегда. - Разницу
throw;иthrow ex;и почему первый предпочтителен. - Как выбирается один из нескольких
catchи почему конкретное идёт перед общим. - Когда заводить свой тип исключения, а когда взять встроенный.
- Как
usingиIDisposableдают детерминированное освобождение ресурсов.
Типичный неверный ответ: «finally нужен, чтобы поймать исключение, если catch не сработал». На деле finally ничего не ловит — он про гарантированную очистку, выполняется независимо от исхода и обходится лишь при жёстком завершении процесса.