Підрозділ 5.2
Блок catch та фільтри винятків
Розглядає форми блоку catch, отримання інформації про виняток через змінну та фільтри винятків із when.
5.2. Блок catch та фільтри винятків
Блок catch є серцем механізму обробки винятків. Він визначає, які саме винятки перехоплюються і яку інформацію про помилку надає розробнику. У C# є три форми блоку catch, а також можливість задати додатковий фільтр через when.

Форма 1: catch без параметрів
Найпростіший варіант — catch без вказання типу. Такий блок перехоплює будь-який виняток, незалежно від його типу:
catch
{
// виконується при будь-якому винятку
}Це зручно на початку або коли тип помилки не важливий. Недолік: немає доступу до інформації про виняток — невідомо, що саме сталося.
Форма 2: catch з типом винятку
Якщо вказати тип у дужках, блок catch перехопить лише цей тип (або його похідні). Винятки інших типів через цей блок не пройдуть:
catch (FormatException)
{
// обробляє лише FormatException
}Тут два блоки catch — кожен обробляє свій тип. Якщо рядок некоректний — спрацьовує FormatException. Якщо число занадто велике — OverflowException. Якщо виникне інший тип помилки — жоден блок не перехопить його.
Важливо: блоки catch перевіряються зверху вниз у порядку оголошення. Спрацьовує перший відповідний.
Форма 3: catch з типом і змінною
Найінформативніша форма: дає доступ до об'єкта винятку через іменовану змінну. Змінна містить усю доступну інформацію про помилку — передусім властивість Message:
catch (FormatException ex)
{
Console.WriteLine(ex.Message); // деталі помилки
}Властивість ex.Message містить зрозумілий опис помилки від CLR. Це особливо корисно для логування: у виробничих системах повідомлення про помилку зазвичай записується у журнал, а не виводиться користувачу напряму.
Фільтри винятків: when
Оператор when дозволяє додати умову до блоку catch. Блок спрацює лише якщо умова повертає true:
catch (ExceptionType ex) when (умова)
{
// виконується лише якщо умова == true
}Якщо умова false — CLR продовжує шукати наступний відповідний catch, навіть якщо тип збігається.
Практичний приклад: в медичній системі ввід пульсу обробляється по-різному залежно від того, чи рядок порожній, чи містить некоректні символи:
Обидва catch обробляють FormatException, але:
- перший — лише якщо
inputпорожній (when (string.IsNullOrEmpty(input))) - другий — у всіх інших випадках
FormatException
Це дозволяє розрізнити різні смислові сценарії для одного типу винятку — без вкладених if у тілі catch.
Антипатерн: «ковтання» винятків
Один із найпоширеніших і найнебезпечніших патернів — блок catch, що не робить нічого або просто виводить повідомлення, але не сигналізує про помилку далі:
// ПОГАНО — помилка «ковтається», програма продовжує роботу з пошкодженим станом:
try
{
int age = int.Parse(input);
SaveToDatabase(age);
}
catch (Exception)
{
// нічого не робимо
}У медичній системі це особливо небезпечно: якщо SaveToDatabase кинула виняток (зв'язок з БД обірвався), а помилка «ковтнута» — дані пацієнта мовчки не зберігаються. Система вважає, що все добре, але картка так і не записана.
Правила:
- Ніколи не залишайте
catchпорожнім у виробничому коді — принаймні логуйте виняток catch (Exception)— тільки на верхньому рівні (main loop, middleware), і лише якщо ви справді знаєте, що з ним робити- Якщо не знаєте, як обробити виняток — використовуйте
throw;, щоб він «спливав» вище
Порядок блоків catch
Кілька блоків catch перевіряються у порядку оголошення. Є одне важливе правило: загальніший тип має йти після конкретнішого. Наприклад, Exception (базовий тип для всіх) повинен бути останнім, інакше він перехопить усе раніше:
Якщо поставити catch (Exception ex) першим — він перехопить усе, і специфічні блоки ніколи не виконаються. Компілятор попередить про недосяжний код.
Підсумок
| Форма | Синтаксис | Що перехоплює |
|---|---|---|
| Без параметрів | catch { } |
Будь-який виняток |
| З типом | catch (FormatException) { } |
Лише вказаний тип |
| З типом і змінною | catch (FormatException ex) { } |
Лише вказаний тип + доступ до ex.Message |
| З фільтром | catch (FormatException ex) when (умова) { } |
Тип збігається і умова true |
Блоки перевіряються зверху вниз. Загальніший тип (Exception) завжди ставте останнім.