Урок № 14. Детализация при обработке ошибок. Часть 1
Детализация при обработке ошибок (исключительных ситуаций)
Доброго времени суток! Настало время еще раз поговорить про обработку ошибок, или исключительных ситуаций, которые могут возникать в наших программах. Мы уже касались этой темы, в том числе и в предыдущем уроке мы использовали механизм обработки ошибок. Давайте вспомним код заключительного примера предыдущего урока:
class Program { /* * Данный метод выводит пользователю приглашение, * указанное в аргументе anOutputStr, получает введенную * с клавиатуры строку, преобразует её в целое число и * возвращает это число */ static int GetNumber(string anOutputStr) { //Вывод приглашения пользователю Console.Write(anOutputStr); //Получение строки string tmpString = Console.ReadLine(); //Преобразование строки в число int tmpArg = Convert.ToInt32(tmpString); return tmpArg; } static void Main(string[] args) { //Потенциально опасный блок try { //Первый вызов метода (получение первого числа) int firstArg = GetNumber("Введите первое число и нажмите клавишу Enter: "); //Второй вызов метода (получение второго числа) int secondArg = GetNumber("Введите второе число и нажмите клавишу Enter: "); //Сложение двух переменных int result = firstArg + secondArg; //Вывод результата Console.WriteLine("Результат сложения введенных чисел: " + result.ToString()); } //Блок обработки ошибок, SystemException - самый общий тип ошибок catch (SystemException) { Console.WriteLine("Во время выполнения программы произошла ошибка, вероятно, были введены некорректные данные!"); } } }
Мы видим, что у нас в программе есть блок потенциально опасного кода (это блок try) и есть блок, который отвечает за обработку ошибок (это блок catch).
В нашей программе он только один на все случаи жизни (на все типы ошибок), в реальной жизни можно использовать несколько разных блоков catch (но об этом я расскажу как-нибудь позже).
Если в блоке потенциально опасного кода возникает ошибка, то его выполнение прекращается и управление переходит к блоку обработки ошибок. В нашем примере, в блоке обработки ошибок мы выводили сообщение в консоль. Но согласитесь, информация в нем не исчерпывающая! Мы не знаем, по какой причине произошла ошибка, в каком конкретно месте программы. Причем, если пользователя может и не нужно перегружать такой информацией, то разработчику она явно необходима, и Вы можете не доводить всю информацию до пользователя, а писать в скрытый лог (журнал ошибок, в данном контексте).
Так как же нам получать больше информации в таких ситуациях? Выход есть! Дело в том, что мы использовали блок обработки ошибок неполноценно! Мы так сказать, не переходили на «личности», в круглых скобках после слова catch мы всего лишь указали тип ошибок (если хотите, класс ошибок), которые обрабатывает это блок.
А теперь я покажу, как можно модифицировать блок обработки ошибок (измененные и добавленные строки выделены):
//Блок обработки ошибок, SystemException - самый общий тип ошибок catch (SystemException ex) { Console.WriteLine("Во время выполнения программы произошла ошибка, вероятно, были введены некорректные данные!"); //Вывод в консоль информации о причине ошибки Console.WriteLine("Причина ошибки: " + ex.Message); }
Что же изменилось? Я добавил объект в круглых скобках после ключевого слова catch, раньше мы указывали там только тип, а теперь мы указали еще и конкретный объект. Эта ситуация схожа указанием формальных параметров в методах (аргументов методов), и теперь, при возникновении ошибки, система не только передаст управление блоку catch, но и «запакует» необходимую информацию по ошибке в объект «ex», к которому мы имеем доступ внутри блока catch. И второе что я сделал, я воспользовался свойством «Message» объекта «ex». В нем хранится системное описание ошибки.
Если Вы модифицируете пример (а точнее блок обработки ошибок) из предыдущего урока как я показывал ранее, у Вас получится примерно следующее:
class Program { /* * Данный метод выводит пользователю приглашение, * указанное в аргументе anOutputStr, получает введенную * с клавиатуры строку, преобразует её в целое число и * возвращает это число */ static int GetNumber(string anOutputStr) { //Вывод приглашения пользователю Console.Write(anOutputStr); //Получение строки string tmpString = Console.ReadLine(); //Преобразование строки в число int tmpArg = Convert.ToInt32(tmpString); return tmpArg; } static void Main(string[] args) { //Потенциально опасный блок try { //Первый вызов метода (получение первого числа) int firstArg = GetNumber("Введите первое число и нажмите клавишу Enter: "); //Второй вызов метода (получение второго числа) int secondArg = GetNumber("Введите второе число и нажмите клавишу Enter: "); //Сложение двух переменных int result = firstArg + secondArg; //Вывод результата Console.WriteLine("Результат сложения введенных чисел: " + result.ToString()); } //Блок обработки ошибок, SystemException - самый общий тип ошибок catch (SystemException ex) { Console.WriteLine("Во время выполнения программы произошла ошибка, вероятно, были введены некорректные данные!"); //Вывод в консоль информации о причине ошибки Console.WriteLine("Причина ошибки: " + ex.Message); } } }
И если вы соберете проект и запустите программу, после чего введете некорректные данные (например, не целое число), т.е. спровоцируете ошибку, то получите нечто похожее:
Да, обратите внимание, причина ошибки указывается системой, и описание не обязательно будет на русском языке, Вы можете столкнуться с английским вариантом, и это нормально, не пугайтесь!
Теперь мы видим еще и причину ошибки. Но пока мы не знаем, в каком конкретном месте произошла ошибка. Хотя, на самом деле, в блок обработки ошибок передается и эта информация, но я пока не хочу вас перегружать и расскажу об этом в другой раз. А следующем уроке, я расскажу как определять место возникновения ошибок, по косвенным признакам.