Г. Шилдт - Полный справочник по C# (1160789), страница 68
Текст из файла (страница 68)
Обработка исключительных ситуаций369} catch (RangeArrayException exc)Console.WriteLine(exc);При выполнении этой программы получаем такие результаты:Длина массива га: 11Содержимое массива га: - 5 - 4 - 3 - 2 - 1 0 1 2 3 4 5Длина массива га2: 10Содержимое массива г а 2 : 1 2 3 4 5 6 7 8 910Сгенерируем ошибки непопадания в диапазон.Нижний индекс не меньше верхнего.Содержимое массива гаЗ: - 2 - 1 0 1 2 Ошибка нарушения границ диапазона.При возникновении ошибки нарушения границ диапазона RangeArray-объект генерирует объект типа RangeArrayException.
Этот класс —- производный от классаA p p l i c a t i o n E x c e p t i o n . Как упоминалось выше, класс исключений, создаваемыйпрограммистом, обычно выводится из класса A p p l i c a t i o n E x c e p t i o n . Обратите внимание на то, что подобная ошибка может обнаружиться во время созданияRangeArray-объекта.Чтобы перехватывать такие исключения, объекты классаRange Array должны создаваться внутри блока t r y , как это показано в программе. Сиспользованием исключений для сообщений об ошибках класс RangeArray теперьнапоминает один из встроенных С#-типов и может быть полностью интегрирован вмеханизм обработки исключений любой программы.Прежде чем переходить к следующему разделу, "поиграйте" с этой программой.Например, попробуйте закомментировать переопределение метода T o S t r i n g O и посмотрите результат.
Попробуйте также создать исключение, используя конструктор поумолчанию, и посмотрите, какое сообщение в этом случае сгенерирует С#.Перехват исключений производных классовПри перехвате исключений, типы которых включают базовые и производные классы, необходимо обращать внимание на порядок catch-инструкций, поскольку c a t c h инструкция для базового класса соответствует любой catch-инструкции производныхклассов.
Например, поскольку базовым классом для всех исключений являетсяException, при перехвате исключения типа Exception будут перехватываться всевозможные исключения. Конечно, как упоминалось выше, использование c a t c h инструкции без аргумента обеспечивает более ясный способ перехвата всех исключений. Однако проблема перехвата исключений производных классов очень важна вдругих контекстах, особенно в случае создания собственных классов исключений.Если нужно перехватывать исключения и базового, и производного класса, поместите первой в catch-последовательности инструкцию с заданием производного класса.
В противном случае catch-инструкция с заданием базового класса будет перехватывать все исключения производных классов. Это правило — вынужденная мера, поскольку размещение catch-инструкции для базового класса перед остальными c a t c h инструкциями сделает их недостижимыми, и они никогда не будут выполнены. В С#недостижимая catch-инструкция считается ошибкой.Следующая программа создает два класса исключений с именами ExceptA иExceptB. Класс ExceptA выводится из класса A p p l i c a t i o n E x c e p t i o n , а классExceptB — из класса ExceptA. Затем программа генерирует исключение каждого типа.370Часть I. Язык С#// Инструкции перехвата исключений производных классов// должны стоять перед инструкциями перехвата исключений// базовых классов.using System;// Создаем класс исключения.class ExceptA : ApplicationException {public ExceptA() : base() { }public ExceptA(string str) : base(str) { }public override string ToStringO {return Message;// Создаем класс исключения как производный// от класса ExceptA.class ExceptB : ExceptA {public ExceptB() : base() { }public ExceptB(string str) : base(str) { }public override string ToStringO {return Message;class OrderMatters {public static void Main() {for(int x = 0; x < 3; x++) {try {if(x==0) throw new ExceptA("Перехват исключения типа ExceptA.");else if(x==l) throw new ExceptB("Перехват исключения типа ExceptB.");else throw new ExceptionO;}catch (ExceptB exc) {// Перехватываем исключение.Console.WriteLine(exc);}catch (ExceptA exc) {// Перехватываем исключение.Console.WriteLine(exc);}catch (Exception exc) {Console.WriteLine(exc);Вот результаты выполнения этой программы:Перехват исключения типа ExceptA.Перехват исключения типа ExceptB.System.Exception: Exception of type System.Exception was thrown,at OrderMatters.Main()Обратите внимание на порядок следования catch-инструкций.
Это — единственноправильный вариант. Поскольку класс ExceptB выведен из класса ExceptA, catchинструкция для исключений типа ExceptB должна стоять перед инструкцией, преднаГлава 13. Обработка исключительных ситуаций371значенной для перехвата исключений типа ExceptA.
Точно так же catch-инструкциядля исключений класса Exception (который является базовым для всех исключений)должна стоять последней. Чтобы убедиться в этом, попробуйте переставить catchинструкции в другом порядке. Это приведет к ошибке при компиляции.Часто catch-инструкцию, определенную для исключений базового класса, успешно используют для перехвата целой категории исключений. Предположим, вы создаете набор исключений для некоторого устройства. Если вывести все эти исключения изобщего базового класса, то приложения, которым не требуется подробные сведения овозникшей проблеме, могли бы просто перехватывать исключение, настроенное набазовый класс, избегнув тем самым ненужного дублирования кода.Использование ключевых слов checkedИ uncheckedВ С# предусмотрено специальное средство, которое связано с генерированием исключений, связанных с переполнением в арифметических вычислениях.
Как вы знаете, в некоторых случаях при вычислении арифметических выражений получается результат, который выходит за пределы диапазона, определенного для типа данных ввыражении. В этом случае говорят, что произошло переполнение результата. Рассмотэим, например, такой фрагмент программы:byte a, b, result;а = 127;b = 127;result = (byte)(a * b ) ;Здесь произведение значений а и b превышает диапазон представления значенийтипа byte. Следовательно, результат вычисления этого выражения вызвал переполнение для типа переменной r e s u l t .С# позволяет управлять генерированием исключений при возникновении переполнения с помощью ключевых слов checked и unchecked.
Чтобы указать, что некоторое выражение должно быть проконтролировано на предмет переполнения, используйте ключевое слово checked. А чтобы проигнорировать переполнение, используйтеключевое слово unchecked. В последнем случае результат будет усечен так, чтобы еготип соответствовал типу-результату выражения.Ключевое слово checked имеет две формы.
Одна проверяет конкретное выражение иназывается операторной checked-формой. Другая же проверяет блок инструкций.checked {expr)checked {// Инструкции, подлежащие проверке.}Здесь expr — выражение, которое необходимо контролировать. Если значениеконтролируемого выражения переполнилось, генерируется исключение типаOverflowException.Ключевое слово unchecked имеет две формы. Одна из них — операторная форма,которая позволяет игнорировать переполнение для заданного выражения. Вторая игнорирует переполнение, которое возможно в блоке инструкций.unchecked372(expr)Часть I. Язык С#unchecked {// Инструкции, для которых переполнение игнорируется.Здесь ехрг — выражение, которое не проверяется на предмет переполнения. В случаепереполнения это выражение усекается.Рассмотрим программу, которая демонстрирует использование как слова checked,так и слова unchecked.// Использование ключевых слов checked и unchecked.using System;class CheckedDemo {public s t a t i c void Main() {byte a, b;byte result;a = 127;b = 127;try {result = unchecked((byte)(a * b ) ) ;Console.WriteLine("Unchecked-результат: " + result);result = checked((byte)(a * b)); // Эта инструкция// вызывает исключение.Console.WriteLine("Checked-результат: " +result); // Инструкция не будет// выполнена.catch (OverflowException exc) {// Перехватываем исключение.Console.WriteLine(exc);При выполнении этой программы получаются такие результаты:Unchecked-результат: 1System.OverflowException: Arithmetic operation resulted in anoverflow.at CheckedDemo.Main()Как видите, результат непроверяемого выражения усекается.
В случае разрешенияпроверки переполнения было бы сгенерировано исключение.В предыдущей программе было продемонстрировано использование ключевыхслов checked и unchecked для одного выражения. На примере следующей программы показано, как можно избежать переполнения при выполнении блока инструкций.// Использование ключевых слов checked и unchecked// для блоков инструкций.using System;class CheckedBlocks {public s t a t i c void Main() {byte a, b;byte result;Глава 13. Обработка исключительных ситуаций373а = 127;b = 127;/try {unchecked {a = 127;b » 127;result = unchecked((byte)(a * b));Console.WriteLine("Unchecked-результат: " + result);a » 125;b = 5;result = unchecked((byte)(a * b ) ) ;Console.WriteLine("Unchecked-результат: " + result);checked {a = 2;b = 7;result = checked((byte)(a * b)); // Все в порядке.Console.WriteLine("Checked-результат: " + result);a = 127;b = 127;result = checked((byte)(a * b)); // Здесь должно// быть сгенерировано// исключение.Console.WriteLine("Checked-результат: " +result); // Эта инструкция не// выполнится.catch (OverflowException exc) {// Перехватываем исключение.Console .WriteLine (exc).;Вот как выглядят результаты выполнения этой программы:Unchecked-результат: 1Unchecked-результат: 113Checked-результат: 14System.OverflowException: Arithmetic operation resulted in an overflow,at CheckedBlocks.Main()Как видите, при выполнении unchecked-блока результат вычисления выраженияпри наличии переполнения усекается.