Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
35
Добавлен:
26.03.2016
Размер:
70.48 Кб
Скачать

Обробка виняткових ситуацій

Блоки try і catch

При розробці програми велика частина помилок, що допускається програмістом, виявляється компілятором. Проте існують помилки, які компілятор не в змозі виявити, тому що вони виникають тільки на етапі виконання програми. Класичний приклад - ділення числа на нуль. Якщо програміст малодосвідчений або просто забув про цю ситуацію, то коли він виконує операцію ділення чисел, то зобов'язаний знати, що дільник може бути і нулем, і це приведе до зупинки програми. Тому в таких випадках програмісти завжди перевіряють дільника на нуль, якщо дільник - ціле число, або на задану програмістом малу величину, менше якої дільник вважається нулем, якщо дільник - число з плаваючою крапкою. Друга характерна помилка програміста - ситуація, коли при роботі з масивами індекс масиву перевищує допустиму межу. Якщо програміст погано або зовсім не розробив контроль введення даних, то на етапі експлуатації програми користувач може ввести дані не за правилами, визначеними в програмі. Знову буде зупинка програми. Чи, наприклад, в програмі йде під’єднання до бази даних, яка вже не існує. Чи відкривається файл, а він пошкоджений. Подібні виняткові ситуації в мові C# називаються виключеннями (винятками). Коли оброблювальне середовище виявляє виключення, воно автоматично перериває виконання програми і видає відповідне повідомлення, щоб надалі можна було б розібратися, чому виникла така ситуація. Але можна уникнути неприємностей, пов'язаних з перериванням роботи програм, якщо самому програмістові на етапі розробки програми потурбуватися про можливе виникнення у тій або іншій ділянці програми виключень, перехопити їх, не давши виконуючому середовищу самому їх обробити і зробити зупин програми, а після перехоплення обробити виниклу ситуацію відповідним чином і або продовжити виконання програми, або завершити програму з виведенням свого повідомлення.

У мові C#, а точніше в середовищі .NET, яка працює не лише з C#, передбачений стандартний підхід до обробки виняткових ситуацій - методика, яка, як і при структурному програмуванні, містить в собі строго визначені кроки з розв’язування проблеми виняткових ситуацій.

  • Розпочнемо з того, що для кожної групи виняткових ситуацій розроблений свій клас, члени якого забезпечують обробку ситуацій цієї групи. Тобто такий клас надає для програміста деталі виняткової ситуації.

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

  • Існує ділянка програми, яка підлягає контролю на виникнення в ній виключення, і ця ділянка називається спеціальним ключовим словом try (намагатися).

  • Існує ділянка програми, яка забезпечує перехоплення та обробку виняткової ситуації, і ця ділянка отримує як назву ключове слово catch (схопити, упіймати).

  • Існує ділянка програми, названа ключовим словом finally (врешті-решт), в якій здійснюються завершальні дії з обробки ситуації.

  • Існує спеціальний оператор throw (викинути), з допомогою якого можна самому в програмі з його допомогою отримати виняткову ситуацію, якщо вона виникає (виняткові ситуації генеруються різними середовищами поза програмою (неявно)), а оператор throw генерує таку ситуацію явно.

Як всі класи спадкуються від базового класу Object, так і всі класи з обробки виключень спадкуються від базового класу System.Exception, який, природно (тому що він - клас), теж спадкується від того ж Object.

Приклад використання обробки виняткової ситуації, коли виняток генерується самою програмою, т. т. явно, приведений в лістингу 9.1, а результат показаний на рис. 9.1.

Лістинг 9.1

using System;

namespace app34_exeption

{

class Program

{

static void Main()

{

Console.WriteLine("Введення рядків завдовжки " + "не більше 5 символів");

int i = (Console.ReadLine().Length);

try

{

if (i > 5)

// Генеруємо виключення

throw new Exception(); // OverflowException();

}

catch (Exception ex) // OverflowException

{

Console.WriteLine("Довжина рядка більше 5 " + "символів");

}

Console.ReadLine();

}

}

}

Рис. 9.1. Демонстрація обробки виключення, коли введені більше 5 символів

У програмі бачимо два блоки обробки виключення, названих ключовими словами try і catch. Кожен блок - ця множина операторів, поміщених у фігурні дужки. Блоки будуються наступним чином: ділянка програми, яка може стати проблемною, береться у блок try. У нашому випадку можуть виникнути проблеми при введенні рядка. Ми хочемо обмежити її довжину п'ятьма символами. Вводимо в блок try ділянку перевірки довжини введеного рядка і не чекаємо від виконуючого середовища ніяких дій з генерації виключення (так воно тут його і не згенерує), а самі вставляємо у блок try оператор trow. Синтаксична конструкція його видна в тексті програми. Exception() - це конструктор базового класу з обробки виключень, який створює з класу об'єкт, елементами якого ми можемо користуватися (поки що ми не скористалися жодним). Раніше відмічалося, що для різних конкретних груп ситуацій існують свої класи-виключення. У цій ситуації можна було б скористатися класом OverflowException, який закоментований в рядку з оператором throw. Цей клас якраз і є різновидом класів-виключень, який дає можливість обробляти переповнення (зокрема, переповнювання рядків по довжині, чим можна було б скористатися). Але часто досить користуватися найзагальнішим класом - Exception, назву якого легко запам'ятати і який теж дає можливість обробки виключень.

У кожного try є пара - catch. Теж блок операторів. У цьому блоці йде власне обробка ситуації. Якщо у блоці try виключення не виникло, блок catch пропускається (це, як пара if...else). Таких пар може бути скільки завгодно: кожну підозрілу ділянку ви можете охопити цією парою. Заголовок блоку catch - це фактично метод з одним параметром типу одного з класів-виключень. У даному випадку цей клас той, який і видав виключення в операторі throw. Тому всередині тіла catch ми можемо користуватися членами класу Exception. Наступна програма, текст якої приведений в лістингу 9.2, і демонструє цей факт. Результат її роботи представлений на рис. 9.2.

Лістинг 9.2

using System;

namespace app34_exeption

{

class Program

{

static void Main()

{

Console.WriteLine("Введення рядків завдовжки не більше 5 " + "символів");

int i = (Console.ReadLine().Length);

try

{

if (i > 5)

// Генеруємо виключення

throw new Exception(); // OverflowException();

}

catch (Exception ex) // OverflowException

{

Console.WriteLine("Довжина рядка більше 5 " + "символів");

Console.WriteLine("Message ={0}", ex.Message);

Console.WriteLine("Source ={0}", ex.Source);

Console.WriteLine("StackTrace ={0}", ex.StackTrace);

Console.WriteLine("TargetSite ={0}", ex.TargetSite);

Console.WriteLine("HelpLink ={0}", ex.HelpLink);

}

Console.ReadLine();

}

}

}

Рис. 9.2. Уточнення причин виникнення виключення

за допомогою членів класу Exception

З рис. 9.2 ми бачимо, що з'явилася додаткова інформація про виключення, яке виникло за рахунок виведення на екран властивостей об'єкта Exception.

  • Властивість Message повідомляє, якого типу виникло виключення.

  • Властивість Source вказує на джерело виникнення виключення.

  • Властивість StackTrace уточнює джерело виникнення виключення: річ у тому, що при роботі програми могли викликатися функції "у глибину", дані про кожен виклик яких запам'ятовуються в стеку програми. Дана властивість дає "трасування" (перегляд шляху по стеку) стека і зрештою показує номер рядка тексту тієї функції, в якій виникло виключення.

  • Властивість TargetSite вказує джерело виникнення виключення. У нашому випадку це Main().

  • Властивість HelpLink дозволяє вказати конкретний URL-адресу, де можна отримати детальнішу інформацію про виникле виключення. За замовчуванням значення цієї властивості - порожній рядок. Але можна самому задати конкретну адресу. Найпростіший спосіб - у блоці catch першим рядком записати ex.HelpLink = "URL-адреса";. Можна створити свій клас з класу Exception і в його конструкторі додати потрібну ініціалізацію властивості HelpLink.

Блок finally

Іноді вимагається визначити ділянку програми, яка буде виконуватися після виходу з блоку try...catch. Наприклад, виняткова ситуація виникла у зв'язку з помилкою, яка приводить до передчасного поверненню з поточного методу. Але в цьому методі міг бути відкритий файл, який треба закрити, або ж встановлено мережеве з'єднання, яке вимагає розриву. Подібні ситуації часто трапляються в програмуванні, і тому для їх вирішення в C# передбачений зручний спосіб: скористатися блоком finally.

Використання блоку finally гарантує, що деякий набір операторів виконуватиметься завжди, незалежно від того, виникло виключення (будь-якого типу) або ні. Для того, щоб задати ділянку програми, яка повинна виконуватися після блоку try...catch, досить вставити блок finally у кінці послідовності операторів try...catch. Далі приведена загальна форма спільного використання блоків try...catch і finally:

try

{

// Ділянка, призначена для обробки помилок

}

catch ()

{

// Обробник виключення

}

finally

{

// Ділянка завершення обробки виключень: закриття потрібних файлів, розрив з'єднань і т. п.

}

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

finally

{Console.WriteLine("Кінець програми");}

Остаточний вигляд програми представлений в лістингу 9.3. Результат її роботи - на рис. 9.3.

Лістинг 9.3

using System;

namespace app34_exeption

{

class Program

{

static void Main()

{

Console.WriteLine("Введення рядків завдовжки не більше 5 " + "символів");

int i = (Console.ReadLine().Length);

try

{

if (i > 5)

// Генеруємо виключення

throw new Exception(); // OverflowException ();

}

catch (Exception ex) // ExceptionOverflow

{

ex.HelpLink="Micrisoft.com";

Console.WriteLine("Довжина рядка більше 5 " + "символів");

Console.WriteLine("Message ={0}", ex.Message);

Console.WriteLine("Source ={0}", ex.Source);

Console.WriteLine("StackTrace ={0}", ex.StackTrace);

Console.WriteLine("TargetSite ={0}", ex.TargetSite);

Console.WriteLine("HelpLink ={0}", ex.HelpLink);

}

finally

{

Console.WriteLine("Кінець програми");

}

Console.ReadLine();

}

}

}

Рис. 9.3. Обробка виняткової ситуації - результат