ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 3188

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Второй путь состоит во включении в исходный текст команды throw без аргумента что приводит к генерации того же объекта исключения, как показано в следующее фрагменте исходного текста:

public void f l ( )

{

try

{

f 2 () ;

}

// Перехват исключения...

catch(Exception e)

{

// ... Частичная обработка исключения ...

Console.WriteLine("Перехват исключения в f l ( ) " ) ;

//... исходное исключение продолжает свой путь по

//цепочке вызовов

throw;

}

}

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

Как реагировать на исключения

Какие у вас имеются варианты при написании catch-блоков? Как объяснялось ранее, вы можете выполнить одно из следующих трех действий:

перехватить исключение; проигнорировать исключение;

частично обработать исключение и повторно его сгенерировать (возможно, с добавлением новой информации) либо просто регенерировать его.

Но какой стратегии необходимо придерживаться при проектировании системы ис­ ключений?

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

Если это возможно — используйте транзакционный подход. Откатите все измене­ ния, которые были сделаны к моменту возникновения ошибки, восстановите фай­ лы в исходное состояние и т.д. Главное правило — не испортить пользовательские данные. Всегда помогайте пользователю в восстановлении, насколько это воз­ можно. Если даже ничего и не получится, то оставит о вас хорошее впечатление...

412

Часть VII. Дополнительные главы


Иногда, когда ошибка не фатальна, достаточно просто поставить пользова­ теля в известность о происшедшем. Например, вы не смогли открыть указан­ ный пользователем файл. Пользователь может быть раздражен и огорчен этим фактом, но, по крайней мере, он сможет продолжить свою работу.

Иногда вы не можете сделать ничего. В этом случае вам остается развести ру­ ками, сообщить об этом пользователю и по возможности грациозно завершить ра­ боту программы.

Обычно это сводится к выводу красивого, соболезнующего, но информативного сообщения об ошибке и завершению программы. Если возможно, предложите пользователю варианты его действий по исправлению ситуации.

Следующий пользовательский класс может сохранить дополнительную информацию, что невозможно в процессе применения стандартных объектов Exception или Appli­ cationException:

//MyException - к стандартному классу исключения добавлена

//ссылка на MyClass

public class MyException : ApplicationException

{

private MyClass myobject;

MyException(string sMsg, MyClass mo) : base(sMsg)

{

myobject = mo;

}

//Позволяет внешним классам обращаться к сохраненному

//в исключении классу

public MyClass MyObject{ get {return myobject;}}

Вернемся вновь к библиотеке функций BrilliantLibrary. Эти функции знают, как заполнять и считывать новые члены класса MyException, тем самым предоставляя информацию, необходимую для отслеживания каждой ошибки. Проблема при таком подходе заключается в том, что только функции BrilliantLibrary могут получить все преимущества от использования новых членов MyException.

Перекрытие методов, имеющихся у классов Exception или Applica­ tionException, может предоставить функциям вне BrilliantLi­ brary доступ к новым данным. Рассмотрим класс исключения из следую­ щей демонстрационной программы CustomException.

//CustomException - создание пользовательского исключения,

//которое выводит информацию в более дружественном формате using System;

namespace CustomException

{

 

 

 

public

class CustomException : ApplicationException

 

{

 

 

 

private

MathClass mathobject;

 

private

string sMessage;

 

Глава 18.

Эти исключительные исключения

413


public CustomException(string sMsg, MathClass mo)

{

 

 

 

 

 

mathobject

= mo;

 

 

 

sMessage =

sMsg;

 

 

 

}

 

 

 

 

 

override

public string

Message

 

 

{

 

 

 

 

 

get{return

String.Format("Сообщение

< { o

} > ,

 

 

 

Объект {l}",

 

 

 

 

sMessage,

 

 

 

 

 

mathobj ect.ToString());}

override

public string

ToString()

 

 

{

 

 

 

 

 

string

s =

Message;

 

 

 

s += "\пИсключение сгенерировано в

";

 

s += TargetSite.ToString(); // Информация

о методе,

 

 

 

// сгенерировавшем

исключение

return

s;

 

 

 

 

}

}

// MathClass - набор созданных мною математических функций public class MathClass

{

private

int nValueOfObject;

private

string sObjectDescription;

public

MathClass(string sDescription, int nValue)

{

 

 

 

nValueOfObject

= nValue;

sObjectDescription =

sDescription;

public

int Value

{get

{return nValueOfObject;}}

//Message - вывод сообщения со значением

//присоединенного объекта MathClass public string Message

{

get

{

return String.Format("({0} = {l})",

sObj ectDescription, nValueOfObject);

}

}

//ToString - расширение нашего пользовательского

//свойства Message с использованием Message из базового

//класса исключения

override

public string

ToString()

{

 

 

string s = Message +

"\n";

s +- base.ToString();

return

s;

 

}

// Вычисление обратного значения 1/x

public double

Inverse()

414

Часть VII. Дополнительные глава


{

if (nValueOfObject == 0)

{

throw new CustomException("Нельзя делить на 0", this);

}

return 1.0 / (double)nValueOfObject;

public class Program

{

public static void Main(string[] args)

try

{

// take the inverse of 0

MathClass mathObject = new MathClass("Value", 0 ) ; Console.WriteLine("Обратное к d.Value равно {О}",

mathObj ect.Inverse() ) ;

catch(Exception e)

{

Console.WriteLine(

"\пНеизвестная фатальная ошибка:\n{0}",

e.ToString());

}

// Ожидаем подтверждения пользователя Console.WriteLine("Нажмите <Enter> для " +

"завершения программы.. . ") ;

Console.Read();

}

Класс CustomException несложен. Он хранит сообщение и объект, как это делал класс MyException ранее. Однако вместо предоставления новых методов для обраще­ ния к этим элементам данных он перекрывает существующее свойство Message, кото­ рое возвращает сообщение об ошибке, содержащееся в исключении, и метод ToString ( ) , возвращающий сообщение и трассировку стека.

Перекрытие этих функций означает, что даже функции, разработанные для перехвата обобщенного класса Exception, получают ограниченный доступ к новым членамданным. Новый класс лучше обеспечить собственными методами для их данных и оста­ вить нетронутыми методы базового класса.

Функция Main () демонстрационной программы начинает с создания объекта MathClass со значением 0, а затем пытается вычислить обратную к нему величину. Не знаю, как вам, а мне не приходилось видеть разумные результаты деления на 0, так что если моя функция вдруг сделает это, я отнесусь к происшедшему с явным недоверием.

На самом деле процессоры Intel возвращают значение 1.0/0.0: бесконечность. Имеется ряд специальных значений с плавающей точкой, используемых вместо генерации исключений в языках, которые не поддерживают их. Эти специаль­ ные значения включают положительную и отрицательную бесконечности и по­ ложительное и отрицательное NaN (Not_a_Number, не число).

(пава 18. Эти исключительные исключения

415