Глава.20 .Исключения.и.управление.состоянием
Интерес также представляет обращение к свойству
Position
класса
Stream
.
Начнем с того, что это виртуальное свойство, поэтому метод
OneStatement
не
«знает», какой код на самом деле следует выполнять, что может привести к любому
исключению. Кроме того, так как класс
Stream
происходит от класса
Marshal-
ByRefObject
, аргумент
stream
может ссылаться на объект-представитель, сам
являющийся ссылкой на объект другого домена приложений. Но другой домен
приложений может оказаться выгруженным, что ведет к появлению исключения
App DomainUnloadedException
.
И конечно, все вызываемые методы мне совершенно неподконтрольны, потому
что они написаны разработчиками из Microsoft. Зато не исключено, что в будущем
специалисты Microsoft поменяют их реализацию, а это приведет к новым типам
исключений, о которых я на момент написания метода
OneStatement
не подозре-
вал. Разве возможно сделать этот метод защищенным от всех возможных ошибок?
Кстати, проблемы создает и противоположная ситуация: блок
catch
способен пере-
хватывать типы исключений, порожденные конкретным типом, поэтому возможно
выполнение кода восстановления совсем для другой ошибки.
Теперь, получив информацию о возможных ошибках, вы, скорее всего, сами
можете ответить на вопрос, почему считается допустимым написание неустойчи-
вого и ненадежного кода — просто учитывать все возможные ошибки непрактично.
Более того, порой это вообще невозможно. Также следует учитывать тот факт, что
ошибки возникают относительно редко. И поэтому было решено пожертвовать
надежностью кода в угоду продуктивности работы программистов.
Исключения хороши еще и тем, что необработанные исключения приводят
к аварийному завершению приложения. И это здорово, так как многие проблемы
выявляются еще на стадии тестирования. Информации, которую вы при этом
получаете (сообщение об ошибке и трассировка стека), обычно достаточно для
внесения нужных исправлений. Разумеется, есть и фирмы, не желающие, чтобы
их приложения аварийно завершались в ходе тестирования или использования,
поэтому разработчики вставляют код, перехватывающий исключение типа
System.
Exception
, базового для всех типов исключений. Другое дело, что при таком под-
ходе возможны ситуации, когда приложение продолжит работу с испорченным
состоянием.
Чуть позже мы рассмотрим класс
Account
, определяющий метод
Transfer
для перевода денег с одного счета на другой. Представьте, что при вызове этого
метода деньги успешно вычитаются с одного счета, но перед зачислением их на
другой счет генерируется исключение. Если вызывающий код перехватывает ис-
ключения типа
System.Exception
и продолжает работу, состояние приложения
окажется испорченным: как на счете
from
, так и на счете
to
будет меньше денег,
чем там должно быть. А так как в данном случае мы говорим о деньгах, порча со-
стояния рассматривается уже не как обычная ошибка, а как проблема системы
безопасности приложения. Продолжая работу, приложение выполнит еще ряд
переводов с одного счета на другой, а значит, порча состояния в рамках прило-
жения продолжится.
521
Продуктивность.вместо.надежности
Можно сказать, что метод
Transfer
должен сам перехватывать исключения типа
System.Exception
и возвращать деньги на счет
from
. Это действительно сработает
для более-менее простого метода
Transfer
. Но если он производит контрольный
отчет изъятых денег или если со счетом одновременно работает несколько потоков,
попытка отменить операцию уже не будет иметь успеха, а только приведет к ново-
му исключению. А это значит, что ситуация не улучшится, а только ухудшится.
Do'stlaringiz bilan baham: |