s
Sesiya.ru

Обработка исключительных ситуаций в C#

Информация о работе

Тема
Обработка исключительных ситуаций в C#
Тип Лекции
Предмет Программирование
Количество страниц 11
Язык работы Русский язык
Дата загрузки 2014-11-20 16:50:38
Размер файла 94.94 кб
Количество скачиваний 43
Скидка 15%

Поможем подготовить работу любой сложности

Заполнение заявки не обязывает Вас к заказу


Скачать файл с работой

Помогла работа? Поделись ссылкой

Обработка исключительных ситуаций в C#

На стадии выполнения программы по разным причинам могут возникать ошибки или непредвиденные проблемы. Это и плохой стиль программирования, и ошибки ввода и другие причины, которые можно классифицировать следующим образом:
1. Ошибки программирования, которые не выявляются на стадии компиляции программы, но которые могут возникнуть на стадии выполнения программы, например, выходы за границы массива, утечка памяти и тому подобное.
2. Ошибки конечного пользователя, которые возникают из-за неправильных действий пользователя. Чаще всего это ошибки ввода данных, превышение допустимых диапазонов чисел и т. д.
3. Ошибки готовности системы, которые возникают на стадии выполнения программы, и которые невозможно предусмотреть, например, попытка открыть не существующий файл, попытка входа в Интернет при отключенной сети и т. д.
Для пользователя было бы неудобно, если бы происходил выход из программы или выключение компьютера из-за неправильной буквы при наборе имени файла или другой аналогичной ошибки.
Перечисленные выше ситуации называются исключительными. На стадии выполнения программы выявляется причина появления исключительной ситуации, и либо пропускается выполнение оператора, вызвавшего ошибку, либо предлагаются меры по устранению причины ошибки с возможностью дальнейшего продолжения выполнения программы.
Такая обработка является общей для многих языков программирования и называется структурированной обработкой исключений (Structured Exception Handling - SEN). Она предоставляет возможность вывода сообщения с описанием проблемы, а также обращения к Интернету для получения более подробного описания проблемы. Исключения могут быть стандартными или пользовательскими. Для стандартных исключительных ситуаций (деление на нуль, выход за границы массива, переполнение при выполнении арифметических операций и т. д.) предусмотрен перехват ошибки с предоставлением пользователю возможности ее устранения без выхода из программы. Исключительные ситуации пользователя некоторые значения или состояния трактуют как ошибки, которые обычно таковыми не являются и зависят только от конкретного приложения. Например, числа могут быть ограничены некоторым диапазоном, могут быть только положительными и т. п.
Если в программе записан блок для перехвата исключительной ситуации, то при ее появлении, либо этот блок предоставляет пользователю возможность исправить ошибку, либо пропускается выполнение оператора, вызвавшего ошибку. В любом из этих случаев выполнение программы не останавливается.
В языке С# для каждой исключительной ситуации должен быть создан класс. Все классы исключительных ситуаций должны быть производными от класса Exception, находящегося в пространстве имен System. Производным от него является класс SystemException, от которого наследуются все стандартные исключительные ситуации. Исключительные ситуации пользователя являются прямыми производными от класса Exception. Классы, созданные для обработки стандартных исключительных ситуаций, приведены в таблице ниже.
Класс исключений Назначение
ArithmeticException Базовый класс для исключений, происходящих при арифметических операциях, например System.DivideByZeroException System.OverflowException.
ArrayTypeMismatchException Вызывается при ошибке записи в массив элемента, имеющего тип несовместимый с фактическим типом массива.
DivideByZeroException Вызывается при попытке деления числа на нуль.
FormatException Несоответствие формата, например, ввод вместо числа буквы.
IndexOutOfRangeException Вызывается, если при попытке обращения к массиву задать индекс меньше нуля или выходящим за границы массива.
InvalidCastException Вызывается при ошибке явного преобразования из одного типа в другой тип.
NullReferenceException Вызывается, если при ссылке на отсутствующий или пустой объект.
OutOfMemoryException Вызывается при неудачной попытке выделения памяти.
OverflowException Вызывается при переполнении выполнения арифметической операции, если не задан режим unchecked.
StackOverflowException Вызывается при переполнении стека из-за слишком большого уровня вложенных вызовов подпрограмм; часто это указывает на ошибки реализации рекурсивных вызовов.
TypeInitializationException Вызывается, когда при инициализации объекта генерируется ошибка, и отсутствует блок catch для ее обработки.
Суть обработки исключительных ситуаций состоит в выявлении места в программе с потенциальным источником ошибки, при появлении которой управление будет передано некоторому блоку, несущему ответственность за устранение проблемы.
Для реализации обработки исключительных ситуаций блок операторов с потенциальным источником одной или нескольких ошибок заключается в фигурные скобки. Перед блоком записывается ключевое слово try (Попытка).
Один блок try может обрабатывать несколько исключительных ситуаций. Для каждой из таких ситуаций оформляется отдельный блок catch, в круглых скобках после которого записывается имя стандартной исключительной ситуации. Блоки catch записываются последовательно друг за другом сразу после конца блока try.
Если исключительную ситуацию (не стандартную и единственную) сформировал программист, то блок catch не содержит имени исключительной ситуации (нет круглых скобок после слова catch), но этот блок должен записываться последним.
Ниже в примере показана стандартная обработка деления на нуль и стандартная обработка переполнения. Добавлена также нестандартная обработка на запрет ввода отрицательных чисел. Для этого случая программист вызывает собственную обработку исключительной ситуации.
if (k < 0 || m < 0) throw new Exception(); //Исключение пользователя
Исключительную ситуацию можно объявить отдельно:
Exception ex = new Exception(); //
Затем ее вызвать оператором
throw (ex);
Если исключительная ситуация вызывается программистом, то блок для ее обработки должен записываться последним.
Обычно ошибочный ввод можно выполнить только один раз. Если ошибка была обнаружена два раза, то она обработана не будет и будет выполнен аварийный останов программы.
Ниже представлена программа, в которой обработка исключительной ситуации заключена в цикл с целью повтора выполнения программы при вводе данных, которые приводят к возникновению исключительной ситуации. Однако количество повторений цикла ограничено. Для этого вставлен счетчик, значение которого сравнивается с заданным количеством повторений (attempts).

static void Main(string[ ] args)
{
int k = 0, m = 0, p = 0, count = 0, attempts = 3; // - attempts сколько попыток
bool flag = true;//
do
{
try
{
Console.WriteLine("Введите k и m");
k = int.Parse(Console.ReadLine());
if (k < 0) throw new Exception();// Исключительная ситуация пользователя
m = int.Parse(Console.ReadLine());
p = (k + m) / (k - m); // Если k = m, деление на 0
flag = false;
}
catch (DivideByZeroException)//
{
count++;//
if (count >= attempts - 1) flag = false; // Количество попыток исчерпано
else Console.WriteLine
("Деление на 0: k = {0} m = {1} повторите попытку с другими k и m",
k, m);
}
catch // Исключительная ситуация, заданная пользователем (k < 0)
{
Console.WriteLine
(" Введено k < 0, повторите ввод");
}
} while (flag);
if (count < attempts) // Все нормально
Console.WriteLine("Ответ p = {0}", p);
else // Все попытки приводили к делению на 0
Console.WriteLine("Деление на 0, все попытки окончились");
Console.ReadKey(); // Останов экрана
}

Ниже представлен вывод программы при разных вариантах ввода.
Нормальный ввод

После ввода возникло деление на нуль

Было выполнено 3 попытки ввода, и во всех была попытка деления на 0

Обработка исключительной ситуации пользователя

Класс Exception обладает рядом свойств, позволяющих уточнить причину возникновения исключительной ситуации. Эти свойства, доступные только для чтения, приведены в таблице ниже.
Свойство Значение
Data Это коллекция пар "ключ/значение", определяемая программистом, может предоставлять дополнительную информацию об исключении. По умолчанию эта коллекция является пустой
HelpLink Это свойство позволяет получать или устанавливать URL-адрес, по которому можно обратиться к справочному файлу или сайту с подробным описанием ошибки
InnerException Это свойство предоставляет информацию о предыдущих внешних исключениях, которые стали причиной текущего вложенного исключения.
Message Это свойство возвращает текст с описанием текущей ошибки. Текст можно задать с помощью конструктора с параметром для класса Exception.
Source Это свойство указывает на имя проекта, который привел к выдаче сообщения об ошибке. В языке CLR указывается сборка.
StackTrace Это свойство описывает последовательность вызовов, которая привела к возникновению исключения.
TargetSite Это свойство возвращает имя подпрограммы, имя файла или тип объекта (подпрограмма – метод, структура и т. д.), которые сгенерировали выдачу сообщения.
В общем случае для обращения к свойствам класса Exception в круглых скобках заголовка catch для соответствующей исключительной ситуации объявляется объект этого класса, а через имя этого объекта можно получить значение свойства. Например, для обработки деления на нуль можно записать заголовок блока catch в виде:

catch (DivideByZeroException ex)

Тогда вывод свойства TargetSite на экран обеспечит оператор

Console.WriteLine("Имя программы: {0}", ex.TargetSite);

Рассмотрим теперь пример с просмотром свойств исключительных ситуаций. Это вариант обработки исключительных ситуаций, при котором в заголовке блока catch объявляется объект класса Exception. Внутри блока выполняется вывод свойств данной конкретной исключительной ситуации для анализа.
Название исключительной ситуации (IndexOutOfRangeException) определяется автоматически. Другие виды исключительных ситуаций надо указывать явно.
Ниже приведена программа подсчета голосов. Задан список номеров кандидатов. При вводе номер кандидата используется в качестве индекса массива, а элемент является счетчиком (для него выполняется операции приращения на 1). Сколько раз был введен номер этого кандидата, столько за него подано голосов.
Установим специальное значение индекса (-20) для нормального завершения программы, для выхода из «вечного» цикл для нормального завершения программы.

static void Main(string[ ] args)
{
int n; // № кандидата
int tot; // Количество кандидатов
Console.WriteLine("
Введите количество кандидатов");
tot = int.Parse(Console.ReadLine());
int [ ] ar = new int[tot]; // Объявление массива счетчиков
while (true)
{
Console.WriteLine("
Введите № кандидата");
try
{
n = int.Parse(Console.ReadLine());
if (n == -20) break; // № кандидата для выхода
ar[n - 1]++; // Индексы в массиве от 0, а номера от 1
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("
Имя программы: {0}", ex.TargetSite);
Console.WriteLine("Файл определения класса : {0}",
ex.TargetSite.DeclaringType);
Console.WriteLine("Тип члена : {0}",
ex.TargetSite.MemberType);
Console.WriteLine("Сообщение : {0}", ex.Message);
Console.WriteLine("Имя проекта : {0}", ex.Source);
Console.WriteLine("
Стек: {0}", ex.StackTrace);
}
finally
{
// Эта блок будет выполняться всегда
}
}
Console.WriteLine("
Результаты голосования
");
for (int i = 0; i < tot; ++i)
Console.WriteLine("Голосов за кандидата {0} {1} ", i + 1, ar[i]);
Console.ReadKey();
}

Если бы не были бы предприняты меры по исключению проверки выхода за пределы допустимых значений индексов, то при вводе индекса, лежащего за пределами допустимых значений, будет выполнен аварийный останов программы с выдачей приведенного ниже сообщения. (Это вариант без блоков try и catch)

В аварийном сообщении имеется строка View Detail, которая позволяет локализовать исключительную ситуацию. Щелчок по этой строке выводит сообщение:

В приведенной программе вставлены блоки try и catch, поэтому на экран можно выводить свойства исключительной ситуации. В заголовке блока объявим переменную ex класса Exception. Через эту переменную можно обращаться к свойствам исключительной ситуации.
Пример распечатки этих свойств показан ниже. Эта распечатка появляется при вводе номера кандидата, выходящего за границу массива (номер кандидата больше заданного количества). При этом после вывода распечатки выполнение программы не останавливается, и продолжается голосование.

Обратите внимание, вывод информации повторяется в окне View Detail, выполненный при аварийном завершении программы. В данном случае аварийного останова не происходит, а неправильный ввод игнорируется. (Русский язык в сообщениях был задан в операторах WriteLine).
И последнее, группу блоков обработки исключительной ситуации может завершать необязательный блок finally, который выполняется всегда, независимо от наличия или отсутствия исключительной ситуации
Покажем пример программы, в которой имеются: блок обработки исключительной ситуации, заданной пользователем, и блок finally. Пусть требуется построить для группы студентов гистограмму ответов на вопрос, как они собираются отвечать на вопросы на предстоящем экзамене. Ответов может быть 3:
1. Откуда-нибудь списать.
2. Получить ответ из Интернета.
3. Подготовиться к экзамену.
Ниже представлен код программы.

class Program
{
static void Main(string[] args)
{
int[] Gist = new int[3];
string st;
int d = 0;
bool flag = true;
Console.Clear();
Console.WriteLine ("
Как вы будете сдавать экзамен?
" +
" 1 - Спишу у кого-нибудь
" +
" 2 - Спрошу в Интернете
" +
" 3 – Подготовлюсь и сдам сам
" +
" 4 - Выход ");
Console.WriteLine("
Выберите вариант ответа");
while (flag)
{
try // Блок генерации исключительной ситуации
{
st = Console.ReadLine();
d = int.Parse(st);
if (d < 1 || d > 4) throw new Exception();// ;
}
catch //
{
Console.WriteLine("
Ошибка! Такого "" + d + "" выбора нет");
// запись ""+ d+"" выводит на экран число d в кавычках
d = 1;
}
finally
{
if (d == 4) flag = false;
else ++Gist[d - 1]; // Накопление гистограммы, индексы от 0
}
}
Console.Clear();
Console.WriteLine("
Студенты обещают на экзамене
" +
"Сколько" + " Что сделают
" +
Gist[0] + " – Спишут
" +
Gist[1] + " - Получат ответ из Интернета
" +
Gist[2] + " - Ответят сами");
Console.ReadKey(); // Останов экрана
} // от Main
} // от class Program
Ниже представлен результат выполнения программы при запуске.

После социологического опроса результат может быть, например, таким.

Если блоков для обработки исключительных ситуаций пользователя требуется более одного, тогда создают пользовательские классы для обработки исключительных ситуаций.
Такой класс является производным от класса Exception и наследует доступные свойства и методы, которые при желании можно перегрузить. Однако в производном классе требуется переопределить конструкторы, определенные в базовом классе и необходимые для данного пользовательского класса для обработки данного исключения.
Ниже приведен пример, в котором обрабатываются исключительные ситуации пользователя и обеспечивающий работу только с положительными числами и не пустыми строками.
В объявлении пользовательского класса конструктор этого класса определен через ссылку на конструктор базового класса. Если при объявлении класса Exception используется конструктор без параметров, то и ссылка на конструктор базового класса должна быть без параметров. В комментариях показано оформление конструктора с параметрами.
Показан пример описания пользовательского класса обработки исключения. В примере описано один дополнительный класс для обработки исключительной ситуации, вторая обработка (запрет ввода пустой строки) выполнена в блоке без параметров, но и для этой обработки можно оформить отдельный класс.

namespace Try_catch
{
// Описание пользовательского класса обработки исключения
class OnlyPositiveNumbers : Exception
{
// Если список при объявлении исключения пуст
public OnlyPositiveNumbers() : base() { }
//public OnlyPositiveNumbers(string str) : base(str) { } // Список не пуст
}
class Program
{
static void Main(string[] args)
{
// Объявление Exception с пустым конструктором
OnlyPositiveNumbers ex1 = new OnlyPositiveNumbers();
// Объявление Exception для конструктора с параметром
//OnlyPositiveNumbers ex1 = new OnlyPositiveNumbers
// ("Число должно быть > 0");
string str;
int n = 0;
try
{
Console.WriteLine("Введите число");
n = int.Parse(Console.ReadLine());
if (n < 0) throw ex1;
Console.WriteLine("Введите строку");
str = Console.ReadLine();
if (str.Length == 0) throw new Exception();
}
catch (OnlyPositiveNumbers)
{
Console.WriteLine("Введено отрицательное число");
}
catch
{
Console.WriteLine("Введена пустая строка");
}
finally
{
Console.WriteLine(" Обработка окончена");
}
Console.ReadKey();
}
}
}

Примеры вывода программы

Введено положительное число, но пустая строка

Введено положительное число и не пустая строка

В примере нет исправлений, требуемых при появлении исключительной ситуации, но добавлен блок finally, в который передается управление при возникновении исключения. Вывод на экран текста в этом блоке указывает последовательность выполнения операторов в блоке при появлении исключительной ситуации.

© Copyright 2012-2020, Все права защищены.