Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

public CarIsDeadException(string cause, DateTime time,

string message, System.Exception
inner) :

base(message, inner)

{

CauseOfError = cause;

ErrorTimeStamp = time;

}

}

Затем необходимо модифицировать метод

Accelerate
с учетом обновленного специального исключения:

throw new CarIsDeadException("You have a lead foot",

DateTime.Now,$"{PetName} has overheated!")

{

HelpLink = "http://www.CarsRUs.com",

};

Поскольку

создаваемые специальные исключения, следующие установившейся практике в .NET Core, на самом деле отличаются только своими именами, полезно знать, что среды Visual Studio и Visual Studio Code предлагает фрагмент кода, который автоматически генерирует новый класс исключения, отвечающий рекомендациям .NET. Для его активизации наберите
ехс
и нажмите клавишу <ТаЬ> (в Visual Studio нажмите <Tab> два раза).

Обработка множества исключений

В своей простейшей форме блок

try
сопровождается единственным блоком
catch
. Однако в реальности часто приходится сталкиваться с ситуациями, когда операторы внутри блока
try
могут генерировать многочисленные исключения. Создайте новый проект консольного приложения на C# по имени
ProcessMultipleExpceptions
, скопируйте в него файлы
Car.cs
,
Radio.cs
и
CarIsDeadException.cs
из предыдущего проекта
CustomException
и надлежащим образом измените название пространства имен.

Затем модифицируйте метод

Accelerate
класса
Car
так, чтобы он генерировал еще и предопределенное в библиотеках базовых классов исключение
ArgumentOutOfRangeException
, если передается недопустимый параметр (которым будет считаться любое значение меньше нуля). Обратите внимание, что конструктор этого класса исключения принимает имя проблемного аргумента в первом параметре типа
string
, за которым следует сообщение с описанием ошибки.

// Перед продолжением проверить аргумент на предмет допустимости.

public void Accelerate(int delta)

{

if (delta < 0)

{

throw new ArgumentOutOfRangeException(nameof(delta),

"Speed must be greater than zero");

// Значение скорости должно быть больше нуля!

}

...

}

На заметку! Операция

nameof
возвращает строку, представляющую имя объекта, т.е. переменную
delta
в рассматриваемом примере. Такой прием позволяет безопасно ссылаться на объекты, методы и переменные С#, когда требуются их строковые версии.

Теперь логика в блоке

catch
может реагировать на каждый тип исключения специфическим образом:

using System;

using System.IO;

using ProcessMultipleExceptions;

Console.WriteLine("***** Handling Multiple Exceptions *****\n");

Car myCar = new Car("Rusty", 90);

try

{

// Вызвать исключение выхода за пределы диапазона аргумента.

myCar.Accelerate(-10);

}

catch (CarIsDeadException e)

{

Console.WriteLine(e.Message);

}

catch (ArgumentOutOfRangeException e)

{

Console.WriteLine(e.Message);

}

Console.ReadLine;

При

написании множества блоков
catch
вы должны иметь в виду, что когда исключение сгенерировано, оно будет обрабатываться первым подходящим блоком
catch
. Чтобы проиллюстрировать, что означает "первый подходящий" блок
catch
, модифицируйте предыдущий код, добавив еще один блок
catch
, который пытается обработать все остальные исключения кроме
CarIsDeadException
и
ArgumentOutOfRangeException
путем перехвата общего типа
System.Exception
:

// Этот код не скомпилируется!

Console.WriteLine("***** Handling Multiple Exceptions *****\n");

Car myCar = new Car("Rusty", 90);

try

{

// Вызвать исключение выхода за пределы диапазона аргумента.

myCar.Accelerate(-10);

}

catch(Exception e)

{

// Обработать все остальные исключения?

Console.WriteLine(e.Message);

}

catch (CarIsDeadException e)

{

Console.WriteLine(e.Message);

}

catch (ArgumentOutOfRangeException e)

{

Console.WriteLine(e.Message);

}

Console.ReadLine;

Представленная выше логика обработки исключений приводит к возникновению ошибок на этапе компиляции. Проблема в том, что первый блок

catch
способен обрабатывать любые исключения, производные от
System.Exception
(с учетом отношения "является"), в том числе
CarIsDeadException
и
ArgumentOutOfRangeException
. Следовательно, два последних блока
catch
в принципе недостижимы!

Запомните эмпирическое правило: блоки

catch
должны быть структурированы так, чтобы первый
catch
перехватывал наиболее специфическое исключение (т.е. производный тип, расположенный ниже всех в цепочке наследования типов исключений), а последний
catch
— самое общее исключение (т.е. базовый класс имеющейся цепочки наследования:
System.Exception
в данном случае).

Таким образом, если вы хотите определить блок

catch
, который будет обрабатывать любые исключения помимо
CarIsDeadException
и
ArgumentOutOfRangeException
, то можно было бы написать следующий код:

// Этот код скомпилируется без проблем.

Console.WriteLine("***** Handling Multiple Exceptions *****\n");

Car myCar = new Car("Rusty", 90);

try

{

// Вызвать исключение выхода за пределы диапазона аргумента.

myCar.Accelerate(-10);

}

catch (CarIsDeadException e)

{

Console.WriteLine(e.Message);

Поделиться с друзьями: