Книга: C# 4.0: полное руководство
Получение производных классов исключений
Получение производных классов исключений
Несмотря на то что встроенные исключения охватывают наиболее распространенные программные ошибки, обработка исключительных ситуаций в C# не ограничивается только этими ошибками. В действительности одна из сильных сторон принятого в C# подхода к обработке исключительных ситуаций состоит в том, что в этом языке допускается использовать исключения, определяемые пользователем, т.е. тем, кто программирует на С#. В частности, такие специальные исключения можно использовать для обработки ошибок в собственном коде, а создаются они очень просто. Для этого достаточно определить класс, производный от класса Exception
. В таких классах совсем не обязательно что-то реализовывать — одного только их существования в системе типов уже достаточно, чтобы использовать их в качестве исключений.
-----------------------------------
ПРИМЕЧАНИЕ
В прошлом специальные исключения создавались как производные от класса Application.Exception, поскольку эта иерархия классов была первоначально зарезервирована для исключений прикладного характера. Но теперь корпорация Microsoft не рекомендует этого делать, а вместо этого получать исключения, производные от класса Exception. Именно по этой причине данный подход и рассматривается в настоящей книге.
------------------------------------
Создаваемые пользователем классы будут автоматически получать свойства и методы, определенные в классе Exception
и доступные для них. Разумеется, любой из этих членов класса Exception
можно переопределить в создаваемых классах исключений.
Когда создается собственный класс исключений, то, как правило, желательно, чтобы в нем поддерживались все конструкторы, определенные в классе Exception
. В простых специальных классах исключений этого нетрудно добиться, поскольку для этого достаточно передать подходящие аргументы соответствующему конструктору класса Exception
, используя ключевое слово base
. Но формально нужно предоставить только те конструкторы, которые фактически используются в программе.
Рассмотрим пример программы, в которой используется исключение специального типа. Напомним, что в конце главы 10 был разработан класс RangeArray
, поддерживающий одномерные массивы, в которых начальный и конечный индексы определяются пользователем. Так, например, вполне допустимым считается массив, индексируемый в пределах от -5 до 27. Если же индекс выходил за границы массива, то для обработки этой ошибки в классе RangeArray
была определена специальная переменная. Такая переменная устанавливалась и проверялась после каждой операции обращения к массиву в коде, использовавшем класс RangeArray
. Безусловно, такой подход к обработке ошибок "неуклюж" и чреват дополнительными ошибками. В приведенном ниже улучшенном варианте класса RangeArray
обработка ошибок нарушения границ массива выполняется более изящным и надежным способом с помощью специально генерируемого исключения.
// Использовать специальное исключение для обработки
// ошибок при-обращении к массиву класса RangeArray.
using System;
// Создать исключение для класса RangeArray.
class RangeArrayException : Exception {
/* Реализовать все конструкторы класса Exception. Такие конструкторы просто реализуют конструктор базового класса. А поскольку класс исключения RangeArrayException ничего не добавляет к классу Exception, то никаких дополнительных действий не требуется. */
public RangeArrayException() : base() { }
public RangeArrayException(string str) : base(str) { }
public RangeArrayException(
string str, Exception inner) : base(str, inner) { }
protected RangeArrayException(
System.Runtime.Serialization.SerializationInfo si,
System.Runtime.Serialization.StreamingContext sc) : base(si, sc) { }
// Переопределить метод ToString()
// для класса исключения RangeArrayException.
public override string ToString() {
return Message;
}
}
// Улучшенный вариант класса RangeArray.
class RangeArray {
// Закрытые данные.
int[] a; // ссылка на базовый массив
int lowerBound; // наименьший индекс
int upperBound; // наибольший индекс
// Автоматически реализуемое и доступное
// только для чтения свойство Length,
public int Length { get; private set; }
// Построить массив по заданному размеру
public RangeArray(int low, int high) {
high++;
if(high <= low) {
throw new RangeArrayException("Нижний индекс не меньше верхнего.");
}
a = new int[high - low];
Length = high - low;
lowerBound = low;
upperBound = --high;
}
// Это индексатор для класса RangeArray.
public int this[int index] {
// Это аксессор get.
get {
if(ok(index)) {
return a[index - lowerBound];
} else {
throw new RangeArrayException("Ошибка нарушения границ.");
}
}
// Это аксессор set.
set {
if(ok(index)) {
a[index - lowerBound] = value;
}
else throw new RangeArrayException("Ошибка нарушения границ.");
}
}
// Возвратить логическое значение true, если
// индекс находится в установленных границах,
private bool ok(int index) {
if(index >= lowerBound & index <= upperBound) return true;
return false;
}
}
// Продемонстрировать применение массива с произвольно
// задаваемыми пределами индексирования,
class RangeArrayDemo {
static void Main() {
try {
RangeArray ra = new RangeArray(-5, 5);
RangeArray ra2 = new RangeArray(1, 10);
// Использовать объект га в качестве массива.
Console.WriteLine("Длина массива rа: " + ra.Length);
for(int i = -5; i <= 5; i++) ra[i] = i;
Console.Write("Содержимое массива ra: ");
for (int i = -5; i <= 5; i++)
Console.Write(ra[i] + " ");
Console.WriteLine("n");
// Использовать объект ra2 в качестве массива.
Console.WriteLine("Длина массива rа2: " + ra2.Length);
for (int i = 1; i <= 10; i++) ra2[i] = i;
Console.Write("Длина массива ra2: ");
for (int i = 1; i <= 10; i++)
Console.Write(ra2[i] + " ");
Console.WriteLine("n") ;
}
catch (RangeArrayException exc) {
Console.WriteLine(exc);
}
// А теперь продемонстрировать обработку некоторых ошибок.
Console.WriteLine("Сгенерировать ошибки нарушения границ.");
// Использовать неверно заданный конструктор,
try {
RangeArray ra3 = new RangeArray(100, -10); // Ошибка!
}
catch (RangeArrayException exc) {
Console.WriteLine(exc);
}
// Использовать неверно заданный индекс,
try {
RangeArray ra3 = new RangeArray(-2, 2);
for(int i = -2; i <= 2; i++) ra3[i] = i;
Console.Write("Содержимое массива ra3: ");
for (int i = -2; i <= 10; i++) // сгенерировать ошибку нарушения границ
Console.Write(ra3[i] + " ");
}
catch (RangeArrayException exc) {
Console.WriteLine(exc);
}
}
}
После выполнения этой программы получается следующий результат.
Длина массива rа: 11
Содержимое массива ra: -5 -4 -3 -2 -1 0 1 2 3 4 5
Длина массива ra2: 10
Содержимое массива ra2: 1 2 3 4 5 6 7 8 9 10
Сгенерировать ошибки нарушения границ.
Нижний индекс не меньше верхнего.
Содержимое массива raЗ: -2 -1 0 1 2 Ошибка нарушения границ.
Когда возникает ошибка нарушения границ массива класса RangeArray
, генерируется объект типа RangeArrayException
. В классе RangeArray
это может произойти в трех следующих местах: в аксессоре get
индексатора, в аксессоре set
индексатора и в конструкторе класса RangeArray
. Для перехвата этих исключений подразумевается, что объекты типа RangeArray
должны быть сконструированы и доступны из блока try, что и продемонстрировано в приведенной выше программе. Используя специальное исключение для сообщения об ошибках, класс RangeArray
теперь действует как один из встроенных в C# типов данных, и поэтому он может быть полностью интегрирован в механизм обработки ошибок, обнаруживаемых в программе.
Обратите внимание на то, что в теле конструкторов класса исключения RangeArrayException
отсутствуют какие-либо операторы, но вместо этого они просто передают свои аргументы классу Exception
, используя ключевое слово base
. Как пояснялось ранее, в тех случаях, когда производный класс исключений не дополняет функции базового класса, весь процесс создания исключений можно поручить конструкторам класса Exception
. Ведь производный класс исключений совсем не обязательно должен чем-то дополнять функции, наследуемые от класса Exception
.
Прежде чем переходить к дальнейшему чтению, попробуйте немного поэкспериментировать с приведенной выше программой. В частности, попробуйте закомментировать переопределение метода ToString()
и понаблюдайте за результатами. Кроме того, попытайтесь создать исключение, используя конструктор, вызываемый по умолчанию, и посмотрите, какое сообщение при этом сформируется стандартными средствами С#.
- Класс System.Exception
- Основы обработки исключительных ситуаций
- Последствия неперехвата исключений
- Обработка исключительных ситуаций - “изящный” способ устранения программных ошибок
- Применение нескольких операторов catch
- Перехват всех исключений
- Вложение блоков try
- Генерирование исключений вручную
- Использование блока finally
- Подробное рассмотрение класса Exception
- Получение производных классов исключений
- Перехват исключений производных классов
- Применение ключевых слов checked и unchecked
- Получение статистики
- Генерирование исключений
- ГЛАВА 4 Обработка исключений
- Получение помощи
- Получение помощи по работе с книгой и компакт-диском
- Получение помощи по Windows SharePoint Services 3.0
- Получение доменного имени
- ГЛАВА 6. Структурированная обработка исключений
- Исключения и обработчики исключений
- 4.8. Получение прав root
- 9.7.4. Иерархии классов и абстрактные классы
- Получение страниц заполненных нулями