Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 50
Текст из файла (страница 50)
что нужно от типа — в данном случае Совр1ех — это возможность участия в булевских выражениях проверки. реализуйте только орегасог сгце и орегасог га1зе. Не реализуйте операцию неявного преобразования в Ьоо1, если только действительно не нуждаетесь в ней. Если окажется, что она все-таки нужна и должна быть реализована, тогда не понадобится реализовывать орегасог сгце и орегзсог га1зе, потому что они будут избыточны.
Если представлены все три операции, то компилятор будет использовать операцию неявного преобразования в Ьоо1 вместо орегасог сгое и орегасог 1а1зе, поскольку вызов первой не является более эффективным, чем остальных, предполагая. что закодированы они одинаково. Резюме В настоящей главе были представлены некоторые полезные рекомендации по перегрузке операций, включая унарные, бинарные и операции преобразования.
Перегрузка операций — одно из тех средств, что делают СЗ мощным и выразительным языком .ХЕТ. Однако только то, что вы можете что-то делать, еще не означает, что вы должны это делать. Неправильное использование операций преобразования и неправильное определение семантики перегрузок других операций вновь и вновь становятся причиной путаницы для пользователей (а наряду с ними — и самого разработчика типа) и нежелательного поведения операций. Когда доходит до перегрузки операций, предусматривайте их лишь столько, сколько необходимо, и не вторгайтесь в область общей семантики разнообразных операций.
Поскольку в СЬБ поддержка перегрузки операций не является обязательной, она присутствует не во всех языках .ХЕТ. Поэтому важно всегда предоставлять явно именованные методы, выполняющие ту же функциональность. Иногда такие методы уже определены в системных интерфейсах, таких как 1Сотрагайуе или 1СопрагаЬ1е<Т>. Никогда не изолируйте функциональность только внутри перегруженных операций, если только не уверены на 100ЕЕ, что код будет использоваться языками .ХЕТ, поддерживающими перегрузку операций. В следующей главе речь пойдет о сложностях и приемах, связанных с созданием безопасного и нейтрального по отношению к исключениям кода в .ХЕТ ггахпечюг1к.
глава 7 Безопасность и обработка исключении реда СЬН включает мощную поддержку исключений. Исключения могут создаваться и генерироваться в точке, где выполнение кода не может быть продолжено, поскольку возникли некоторые исключительные условия (обычно сбой метода или некорректное состояние).
Написание безопасного в отношении исключений кода— настоящее искусство, которым следует овладеть. Было бы ошибкой предполагать, что единственной задачей во время написания безопасного к исключениям кода является генерация исключения при возникновении ошибки и перехват его в некоторой точке. Такое представление безопасного к исключениям кода недальновидно и является прямым путем к безысходности. На самом деле безопасное к исключениям кодирование означает гарантию целостности системы перед лицом возникающих исключений.
Когда исключение генерируется, исполняющая система последовательно "раскручивает" стек, выполняя очистку. Ваша задача, как программиста — структурировать код таким образом, чтобы при раскручивании стека целостность состояния объектов не нарушалось. В этом суть приемов безопасного к исключениям кодирования. В настоящей главе будет показано, как СЬК обрабатывает исключения, и представлен механизм, участвующий в обработке исключений. Однако обработка исключений этим не ограничивается. Например, будут рассмотрены, части кода, которые должны обрабатывать исключения, а также продемонстрированы способы преодоления ловушек, поджидающих на этом пути. Что более важно — будет показано, как при написании безопасного к исключениям кода вообще обойтись без обработки исключений.
Такой код обычно называют нецшрольным по огпношению к исключениям. Это может показаться сюрпризом, но читайте дальше, и вы ознакомитесь с деталями. Как С~В трактует исключения Как только исключение сгенерировано, СЬК начинает процесс итеративной "раскрутки" стека исключений, фрейм за фреймом'.
Делая это, она очищает все объекты. ' Говоря коротко, когда метод вызывается в процессе выполнения программы, в стеке строится фрейм, содержащий переданные параметры и все локальные параметры метода. Прн возврате из метода этот фрейм удаляется. Если метод вызывает другой метод н тд., то новые фреймы создаются над текущим. формируя вложенную структуру фреймов вызова.
190 Глава 7 локальные по отношению к каждому фрейму стека. В некоторой точке фрейм в стеке может иметь обработчик исключения, зарегистрированный именно для типа сгенерированного исключения. Как только среда СЬК достигает этого фрейма, она вызывает этот обработчик, чтобы справиться с ситуацией. Если стек полностью раскручен, а обработчик для сгенерированного исключения не найден, может быть инициировано событие "необработанное исключение" для текущего домена приложения, и выполнение приложения будет прервано.
Механизм обработки исключений в С№ Если ранее приходилось иметь дело с исключениями в С-подобных языках, таких как С++, дача или даже С/С++ с расширениями )Ы)сгоэой, предназначенными для обработки исключений ( Сгу/ сагсЬ/ 11па11у), то базовый синтаксис исключений в СЗ должен выглядеп знакомо. В этом случае можно пропустить несколько следующих разделов или просмотреть их бегло.
Области, которые существенно отличают СЗ от других языков в стиле С, специальным образом отмечены. Генерация исключений Акт генерации исключения достаточно прост. Нужно просто выполнить оператор ЬЬгоы, параметром которого является генерируемое иснлючение. Например, предположим, что написан собственный класс коллекции, позволяющий пользователям обращаться к элементам по индексу, и необходимо уведомить пользователя, когда в параметре передается неверный индекс. Для этого можно сгенерировать исключение АтдпюепСОпСОГрапде, как показано в следующем коде: роЬ11с с1аэз Иусо11естаоп ( риЬ11с оЬ)есг Оео1гею( Епе 1пбех ) тт( апбех < О )) гпбех >= соопв ) ( сьгон пен Атдоюепеоисожапдеехсерстоп() ) О Выполнить какую-то полезную работу ) рг1уаье ьпв соопс) ) Исполняющая система может также генерировать исключения как побочный эффект от выполнения кода.
Примером сгенерированного системой исключения может служить ))п11нетегепсеЕхсере1оп, которое возникает при попытке обращения к полю или вызова метода на обьенте, когда фактически ссылка на объект не существует. Изменения, касающиеся необработанных исключений, которые появились в .НЕТ 2.0 Когда исключение сгенерировано, исполняющая система начинает искать в стеке соответствующий этому исключению блок сассЬ. Проходя по стеку, она раскручивает ею, очищая по пути каждый фрейм.
Если поиск завершается в последнем фрейме потопа, а обработчик исключения не найден, в этой точке исключение считается необработанным. Что случится дальше— зависит от того, какая версия .)дЕТ г гэтпе~чог)т используется кодом. Безопасность и обработка исключений 191 На заметку! Для необработанных исключений можно установить специальный фильтр, зарегистрировав делегат с помощью Аррровауп. 0ппапб1ебехсерсаоп. Когда необработанное исключение проходит сквозь весь стек, этот делегат будет вызван и получит экземпляр цппапб1ебЕхсергаопЕуепгАгдз, На заметку! Среда СЫ транслирует необработанные исключения, проходящие через статические конструкторы.
Более подробно эта тема раскрывается в разделе "Исключения, сгенерированные в статических конструкторах" далее в главе. В .НЕТ 1. 1 проектировщики СЬН решили "проглатывать" некоторые необработанные исключения в интересах повышенной стабильности. Например, если финализатор генерирует исключение в .НЕТ 1. 1 вместо прерывания потока финализатора и всего процесса, то исключение "проглатывается" и не позволяет уничтожить поток финзлизатора или прервать процесс. Аналогично, если необработанное исюпочение проникает в поток, отличающийся от главного потока, этот поток прерывается, не затрагивая остального процесса. В потоке, управляемом пулом потоков, исключение "проглатывается", а поток возвращается в пул — такое поведение аналогично обработке исключения в потоке финализатора.
Если необработанное исключение распространяется вверх из главного потока, оно ведет себя, как и ожидалось, при этом либо прерывается процесс, либо отображается диалог отладки ЛТ, спрашивающий у пользователя, что он желает предпринять. Такое поведение выглядит неплохо в принципе, но в реальности дает результат, обратный ожидаемому. Вместо обеспечения повышенной стабильности, система приходит в нестабильное состояние, поскольку код выполняется в недетерминированном состоянии. Например, представим финалнзатор, выполняющий некоторую ответственную работу. Предположим, что на полпути выполнения этой работы сгенерировано исключение.
Вторая половина работы финализатора останется невыполненной. Система находится в потенциально нестабильном, незавершенном состоянии. Внешне все продолжает работать нормально, хотя состояние системы может быть далеким от нормы. На практике зто вызывает значительную нестабильность, поскольку источники ошибок трудно найти, раз исключения "проглатываются". Отладка этих проблем отличается повышенной сложностью, потому что точка во времени, где возникло исключительное условие, обычно находится задолго до того момента, когда замечена результирующая нестабильность. В .НЕТ 2.0 эта проблема решена за счет требования, чтобы любое необработанное исключение.
кроме Аррровааппп1оабехсеркуоп и тьгеабАьогсехсеркаоп, вызывало прерывание потока. Звучит грубо, но на самом деле это именно то поведение, которое должно показывать необработанное исюпочение. В конце концов, это необработанное исключение. Теперь, если поток прерывается, как и должен, зто означает генерацию красного флажка в точке исключения, что позволяет немедленно обнаружить проблему и устранить ее. Это всегда хорошо. Всегда желательно, чтобы ошибки проявились как моясно раньше; никогда не следует "глотать" исключения, позволяя системе работать, как ни в чем не бывало. На заметку! Если все-таки возникнет желание эмулировать поведение .НЕТ 1.1 в отношении необработанных исключений, то его можно затребовать, добавив следующую опцию в конфигурационный файл приложения: <зузгев> <гппепве> <1еозсуспнапб1ебахсеркаопго11су епаЬ1еб "1"/> </гппеаве> </зузгев> 192 Глава 7 Обзор синтаксиса операторов ~гу, салоп и й~па11у Код внутри блока Ггу защищен от исключений так, что если исключение сгенерировано, то исполняющая система ищет подходящий блок сагсЬ, чтобы его обработать.












