OOP Course
Сьогодні

Підрозділ 5.1

Конструкція try..catch..finally

Пояснює конструкцію try..catch..finally, порядок виконання блоків, аварійне завершення програми та випадки, коли краще використати умовну перевірку.

5.1. Конструкція try..catch..finally

У реальних програмах завжди є ситуації, які важко або неможливо повністю передбачити під час написання коду. Файл може не існувати, мережа може обірватися, користувач може ввести не число, а текст. Такі позаштатні події під час виконання програми називаються винятками (exceptions).

У C# передбачено спеціальний механізм обробки винятків — конструкція try...catch...finally. Вона дозволяє виявити аварійну ситуацію, обробити її або зробити необхідне завершення ресурсів — і продовжити виконання програми замість аварійного завершення.

Що таке виняток

Виняток — це об'єкт, який середовище виконання CLR (Common Language Runtime) автоматично створює, коли відбувається помилка, і «викидає» вгору по стеку викликів у пошуках обробника. Якщо обробника немає — програма аварійно завершується.

Кожен виняток є екземпляром класу, що успадковується від System.Exception. Наприклад:

  • DivideByZeroException — ділення цілого числа на нуль
  • FormatException — некоректний формат рядка при конвертації
  • NullReferenceException — звернення до null-посилання
  • IndexOutOfRangeException — вихід за межі масиву

Структура try...catch...finally

Загальна форма конструкції:

try
{
    // код, в якому може виникнути виняток
}
catch
{
    // виконується, якщо виняток виник
}
finally
{
    // виконується завжди — і при винятку, і без нього
}

Схема виконання try..catch..finally

Логіка роботи:

  1. Виконуються інструкції у блоці try.
  2. Якщо жодного винятку не виникло — після try виконується finally, блок catch пропускається.
  3. Якщо виняток виник — виконання try зупиняється на місці помилки. CLR шукає відповідний блок catch.
  4. Якщо catch знайдено — він виконується, потім finally.
  5. Якщо catch не знайдено — finally все одно виконується, а потім програма аварійно завершується.

Перший приклад: парсинг даних пацієнта

Уявімо, що реєстратура вводить вік пацієнта як рядок із зовнішньої форми. Якщо рядок містить нецифрові символи, метод int.Parse() кине FormatException:

Без конструкції try...catch цей код завершився б аварійно з FormatException. З обробником — програма перехоплює помилку, виводить повідомлення і продовжує роботу далі.

Зверніть увагу: рядок "Програма продовжує роботу." виводиться завжди — виняток перехоплено, а не проігноровано.

Поширення винятку по стеку викликів

Виняток не обов'язково обробляється там, де виник. Якщо в методі немає try...catch, виняток «спливає» вгору — до того методу, який викликав поточний. CLR послідовно перевіряє кожен рівень стека, поки не знайде відповідний catch.

Якби у ParseAge не було catch, виняток піднявся б до RegisterPatient. Якби і там не було — до точки виклику, і далі. Це дозволяє централізувати обробку помилок у потрібному місці ієрархії.

Варіант: тільки try...catch (без finally)

Блок finally не є обов'язковим. Конструкція try...catch без finally — найпоширеніший варіант:

Цикл продовжується навіть після помилки: кожен запис обробляється незалежно. Некоректні дані пропускаються, але програма не зупиняється.

Варіант: тільки try...finally (без catch)

finally можна використовувати без catch — якщо ловити виняток не потрібно, але важливо гарантувати виконання завершального коду (наприклад, закрити файл або звільнити ресурс):

Важливо: конструкція try...finally без catch не перехоплює виняток — вона лише гарантує виконання блоку finally перед тим, як виняток продовжить поширюватися вгору. Якщо у жодного виклику не буде catch, програма все одно аварійно завершиться.

Умовні конструкції замість try...catch

Частину потенційних помилок можна уникнути, перевіривши умову заздалегідь, — і це ефективніший підхід, ніж catch. Механізм винятків в CLR витрачає значно більше ресурсів, ніж звичайна умовна перевірка, тому не варто використовувати try...catch там, де можна перевірити коректність даних до виконання операції.

Наприклад, для парсингу існують TryParse-методи:

Метод int.TryParse(string, out int) повертає true, якщо конвертація успішна, і false — якщо ні. При успіху змінна age містить результат. Жодного винятку не виникає — обидва сценарії опрацьовуються нормальним потоком виконання.

Порівняйте: try...catch з int.Parse — це «обробити аварію після зіткнення». TryParse — це «перевірити умови безпеки перед стартом». Другий підхід і семантично коректніший, і продуктивніший.

Коли використовувати try...catch, а коли умовні перевірки

Ситуація Рекомендований підхід
Парсинг числа з рядка TryParse + умова
Перевірка на null if (x != null) або ?.
Робота з файлом / мережею try...catch
Звернення до бази даних try...catch
Зовнішній код, що може кинути виняток try...catch
Гарантоване звільнення ресурсу try...finally або using

Правило просте: якщо помилку можна передбачити і перевірити — перевіряйте. Якщо помилка залежить від зовнішніх умов (файлова система, мережа, зовнішній сервіс) — обробляйте через try...catch.

Підсумок

  • try — блок захищеного коду, де може виникнути виняток
  • catch — обробник винятку; виконується лише якщо виняток виник
  • finally — гарантовано виконується завжди, незалежно від винятку
  • Виняток поширюється вгору по стеку до першого відповідного catch
  • Для передбачуваних помилок краще використовувати умовні перевірки (TryParse, null-перевірки) — це ефективніше, ніж catch
Розроблено Tomka Yurii · © 2026 ·