Урок № 15. Детализация при обработке ошибок. Часть 2


Определение места возникновения ошибки

Доброго времени суток! В этом уроке я кратко расскажу о технике поиска места возникновения ошибок в компьютерных программах, написанных на C#. Для примера я буду использовать программу из предыдущего урока.

Сразу Вас «обрадую», почти всегда, на поиск причины и места возникновения ошибки уходит больше времени, чем на исправление самой ошибки.

Так вот, вернемся к делу! В предыдущем уроке мы научились определять причину возникновения ошибки, по той информации, которую предоставляет система (в нашем случае, дело было в том, что пользователь вводил не целочисленное значение, а какую-то другую строку). В этом же уроке, мы научимся определять место ее возникновения по косвенным признакам. И так, вспомним код программы из предыдущего урока:

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);
        }
    }
}

А теперь результат работы программы при вводе некорректного значения:

Работа программы, при вводе некорректных данных

Работа программы, при вводе некорректных данных

Что мы видим на экране? Мы видим, что пользователю выведено приглашение ввести первое число. Программа обрабатывает ввод, и потом выполнение блока try прерывается, потому что видно, что дальше выполняется блок catch, т.е. блок обработки ошибок. Мы знаем, что за описанную функциональность (вывод приглашения, получение и обработка введенных данных), отвечает метод «GetNumber», который просто вызывается в блоке try. Соответственно, мы можем сделать вывод, что ошибка происходит именно в этом методе. Значит начинаем подробно разбирать его!

/*
* Данный метод выводит пользователю приглашение,
* указанное в аргументе anOutputStr, получает введенную
* с клавиатуры строку, преобразует её в целое число и
* возвращает это число
*/
static int GetNumber(string anOutputStr)
{
    //Вывод приглашения пользователю
    Console.Write(anOutputStr);

    //Получение строки
    string tmpString = Console.ReadLine();

    //Преобразование строки в число
    int tmpArg = Convert.ToInt32(tmpString);

    return tmpArg;
}

Моделируем работу метода по шагам и ищем место, в котором его работа была прервана. Сначала должно быть выведено сообщение пользователю. Оно и было выведено, значит ошибка произошла где-то дальше! Соответственно, подозрение со строчки кода, представленной ниже, снимается:

//Вывод приглашения пользователю
Console.Write(anOutputStr);

Идем дальше, за что отвечает следующая строка кода?

//Получение строки
string tmpString = Console.ReadLine();

За получение данных после ввода их пользователем с клавиатуры и сохранения этих данных в переменной «tmpString». А теперь вспомним сообщение о причине ошибки. Там сказано, что входная строка имела некорректный формат. Вряд ли ошибка произошла во время выполнения текущего шага, ведь на нем строка просто считывается с клавиатуры и сохраняется в переменной, и не важно что ввел пользователь…Значит, идем дальше!

//Преобразование строки в число
int tmpArg = Convert.ToInt32(tmpString);

На данном шаге, выполняется преобразование введенной строки в число. И вот тут, формат введенных данных уже имеет значение! Ведь не каждую строку можно преобразовать в число! Например слово «медведь» в число не преобразуешь! Тем более что у нас есть четкое требование, что число должно быть целым… Что накладывает еще большие ограничения на входные данные. Таким образом, мы понимаем, что ошибка произошла в строке кода:

//Преобразование строки в число
int tmpArg = Convert.ToInt32(tmpString);

Вот мы и нашли место возникновения ошибки. А так как метод «GetNumber» вызывается дважды, то и ошибка может проявиться в двух случаях (в каком из них она произошла в нашем примере, догадаться не сложно по тем же косвенным признакам).

В подобных ситуациях можно найти различные выходы. Например, перед обработкой входных данных их можно сначала проверить, и в случае обнаружение какого-либо дефекта – запросить их еще раз. Или локализовать обработку исключительных ситуаций в пределах метода, в котором возникает ошибка и тому подобное. Но это уже разговор на другую, и к тому же весьма обширную, тему, которую мы оставим на будущее! А следующий урок будет чисто практический, что бы разгрузить Вас от потока информации…

Перейти к следующему уроку