C#. Генерация исключений

Генерация исключений

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

//Класс, для описания некого человека
class Person
{
    //Конструктор
    public Person(string aName, int anAge)
    {
         name = aName;
         age = anAge;
    }

    //Возвращает, или устанавливает имя
    public string Name { get { return name; } set { name = value; } }
    //Возвращает, или устанавливает возраст
    public int Age { get { return age; } set { age = value; } }
    //Возвращает, или устанавливает рост
    public int Height { get { return height; } set { height = value; } }

    private string name; //Имя
    private int age;     //Возраст
    private int height;  //Рост
}

Как видите, в примере представлен класс, описывающий некую персону. Обратите внимание, в классе есть конструктор, который принимает имя человека и его возраст. А теперь, давайте подумаем, что будет если при создании объекта этого класса мы укажем в качестве возраста, например, «-21»? Согласитесь, отрицательным возраст быть не должен! Но ничего не помешает нам так поступить! В результате мы получим нарушение логической целостности данных, а программа продолжит выполняться.

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

Вывод напрашивается сам собой: нужно обрабатывать входные данные! Это действительно так, но обработать их мы сможем, а вот как сообщить системе, что мы получили некорректные данные? Ну, допустим в неком методе, мы можем вернуть специальное значение, которое даст понять, что работа не выполнена из-за некорректных входных данных. Но этот вариант не подойдет для конструкторов или методов set свойств (они ведь не могут возвращать никаких значений)! Да и не в каждом методе есть возможность вернуть специфическое значение…

Одним словом, нужен механизм, позволяющий грамотно информировать о нештатных ситуациях. Для этого предназначен оператор throw. Он информирует систему, прерывает выполнение программы, и «выбрасывает в эфир» объект специфического класса (класса «Exception» из пространства имен «System», либо его наследника) с информацией о причине сбоя.

А теперь, давайте посмотрим как это работает на практике, для этого, модернизируем конструктора класса «Person» следующим образом:

//Конструктор
public Person(string aName, int anAge)
{
    name = aName;

    //Если указан отрицательный возраст
    if (anAge < 0)
    {
        throw new Exception("Отрицательный возраст");
        //Дальше, конструктор выполняться не будет...
    }

    age = anAge;
}

Как видно из примера, входной параметр конструктора, обозначающий возраст, проверяется, и если он имеет некорректное значение, выполняется оператор throw. После ключевого слова throw идет создание объекта класса «Exception».

Один из конструкторов класса «Exception» принимает строковое описание ошибки, им мы и воспользовались.

Обратите внимание, что оператор throw чем-то похож на оператор return, после его выполнения, ни один оператор нашего конструктора не выполнится! Таким образом, если мы напишем примерно такой код:

try
{
    //Возникнет ошибка
    Person somePerson = new Person("Иван", -21);

    //Какие-то другие операторы...
}
catch (Exception ex)
{
    //Обработка ошибок
    Console.WriteLine(ex.Message);
}

Объект «somePerson» не будет создан из-за ошибки, выполнение блока try будет прервано, а управление передано в блок catch. И мы сразу узнаем, что произошла какая-та ошибка, и нарушения логической целостности данных в нашей программе не будет! На самом деле, мы можем создать свой класс для представления информации об ошибке, и использовать его, но об этом я расскажу в следующей статье…

Добавить комментарий