Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 56
Текст из файла (страница 56)
Сопзо1е.нггтентпе( "аббгевя = (Огн)", табто1пго.аббтевв Сопяо1е .Нт1тег 1пе ( "згнаюе = ( 0 ) ", табто1пго.ягнаие )) Сопяо1е.мтгтеЬТпе( "о101авябгбеч1се = (О)", таббо1пго.о1С1аяяОТОеч1се ); Сопзо1е.нггтентпе( "1трБоЬчегз1оп = (О)", габто1пго.1юрноЬчегвтоп ); СОПВО1з.мтттЕЕ1ПЕ( тюалогаотОГЕГ = (О)", таб1о1пто.иапогастотет ); ) табгоНапб1е.Ыврояе(); Безопасность и обработка исключений 21 1 ]О111арогС( "1гргоря.ср1" )] Рггчате якагсс ехСегп яагеВ1иегооСЬВаб1оГ1пбнапб1е В1иегооСЬГТпбГсгяСВаб1о] ]Мзгяпа1ля]ипазпаоебтуре.ЬРЯСгисг)] В1иеСооСЬГгпбпаб1оРагавя РЬСггр, оиг ЯасеГ11ензпб1е РЬВабсо ); ]О111кРОгг] "1гргоря.ср1 )] рггчаге яСагсс ехтегп и1пС32 В1иегооСЬОеткабсо1пго) Яагег11еНапб1е Ьпабсо, тес В1иетооСЬВабсо1пто Ркабго1пго )г ) Суть этого примера заключена в яасеВ1иетооСЬВабаоГ1пбНапб1е.
Его можете унаследовать непосредственно от Яагенапб1е, но исполняющая система предлагает два вспомогательных класса, ЯагеНапб1е2егоогМТпияОпе1я1пча11б и Яагенапб1еМТпияОпе1я1пча1гб, от которыхвыполнятьнаследование удобней. Внимание! Будьте осторожны, имея дело с функциями у)лп32 через Рдпчойе, и всегда тщательно читайте документацию, чтобы знать, чему равно неверное значение дескриптора. Интерфейс у)йп32 АР) известен путаницей в этом вопросе.
Например, уу)п32-функция сгеасеГ11е дпя обозначения неудачи возвращает -1, а функция сгеасекчепс в случае ошибки возвращает дескриптор НОВЕ В обоих случаях типом возвращаемого значения является ВАНОЬВ. При разработке собственного наследника Яагенапб1е необходимо помнить о нескольких вещах.
° Применяйте требование безопасного доступа к классу, копюрому придется вызываясь неуправляемый код. Разумеется, вы не обязаны делать это, если в действительности не обращаетесь к неуправляемому коду, но вероятность создания наследника Яагенапб1е без вызова неуправляемого кода весьма невелика. ° Предуслквприеайте конструктор по умолчанию, который инициализирует наследника яасенапб1е. Обратитевнимание,что яасеВ1иесоосЬНабгоГТпбНапб1е объявляет приватный конструктор по умолчанию. Поскольку уровень Р/1пчо1се обладает особыми полномочиями, он может создавать экземпляры объекта даже в случае приватного конструктора. Приватный конструктор удерживает клиентов от создания экземпляров беэ вызова функций т)У)п32, создающих лежащий в основе ресурс.
° Переопределлйте виртуальное сзойстпво 1я пча11с1. В данном случае в этом не было необходимости, поскольку базовый класс Яасенапб1езегоОгиспияОпе1ятп ча11б делает это самостоятельно. ° Переопределяшпе виртуальный мегпод Ве1еаяенапб1е, используемый для очисгпки ресурса. Обычно в нем осуществляется вызов Р/1пчо1се для освобождения неуправляемого ресурса. В данном примере вызывается В1иекооСЬГ1пбкабсоС1ояе. Обратите внимание, что при объявлении метода для вызова Р/1пчо1се применяется контракт надежности, поскольку метод Не1еаяеНапб1е вызывается в контексте СЕВ.
Вдобавок разумно применить к методу атрибут Яирргеяяипаападебсоб еяесигТСуАССг].Ьите, чтобы предотвратить проверку стека средством САВ )Сос1е Ассевв Весит)ту — безопасность доступа кода) среды СЬЛ при каждом вызове. Но помните, что это подразумевает защищенность самого кода. После определения наследника Яагенапб1е вы готовы использовать его через объявления Р/1пчо)се. В предыдущем примере объявлялся метод В1иекооСЬГТпбГТгяСНабао длл вызова через Р/1пчо)се.
Если посмотреть на описание этой функции в М1сгояой Пете)орег Хетсчог)с )Мя)Ь]). то станет ясно, что она возвращает тип ВЬВВТООТН ВАР10 Г1НР, 212 глава 7 который представляет собой дескриптор внутреннего объекта перечисления устройств В!цетоойь Во времена .А!ЕТ 1.1 тип возврата метода потребовалось бы объявить как Тпгргг. Начиная с .!чЕТ 2.0, в качестве типа его возврата указывается БзгеН1пегоогппзг!1ор1пг!Нзпг!1е, а уровень маршализации Р/!пто!ге обрабатывает все остальное. Теперь дескриптор перечисления защищен от утечки исполняющей системой на случай каких-либо асинхронных исключений, исходящих от виртуальной системы выполнения. Внимание! При маршализации между методом СОМ или функцией УУ!п32, которая возвращает дескриптор, содержащийся в структуре (в противоположность возврату просто дескриптора), уровень функциональной совместимости не предоставляет поддержки работы с наследниками Багенапг!1е.
В таких редких случаях нужно вызывать метод Беснапг!1е наследника Багенапг!1е после получения структуры от функции или метода СОМ, чтобы экземпляр БзуеНзпг!1е смог управлять временем жизни неуправляемого ресурса. Однако если приходится поступать подобным образом, необходимо убедиться, что операции, создающие дескриптор, и последующий вызов Беснзпг!1е происходят внутри СЕН, чтобы ничто не могло прервать процесс выделения ресурса и присваивания дескриптора объекту Багензпг!1е. В противном случае есть вероятность возникновения утечки ресурсов. Создание пользовательских классов исключений У Бузгегл.
Ехсерг1оп имеются три общедоступных конструктора и один защищенный. Первый — это конструктор по умолчанию, который на самом деле мало что делает. Второй — конструктор, принимающий ссылку на строковый объект. Строка представляет собой общее, определяемое программистом сообщение, которое можно рассматривать как более дружественное к пользователю описание исключения. Третий конструктор также принимает строку сообщения, как и второй, но вдобавок принимает ссылку на другой объект Ехсерсаоп. Ссылка на другое исключение позволяет отслеживать исходные иснлючения, когда внутри блока тгу одно исключение транслируется в другое.
Хорошим примером может служить ситуация, когда исключение не обрабатывается, а просачивается вверх, во фрейм стека статического конструктора. В этом случае исполняющая система генерирует исключение Туре1паг1а11загаопЕхсергаоп. но только после установки внутреннего исключения в исходное исключение, чтобы тот, кто перехватывает Туре1п1Г1а11ззсаопЕхсергаоп.
по крайней мере, знал, чем вызвано исключение изначально. И, наконец, защищенный конструктор позволяет создавать исключение из объекта Бегаа11заг№оп1пго. Серивлизуемые исключения создаются, чтобы их можно было использовать через границы контекстов, например, с .!чЕТ решет!па. Это значит, что пользовательские классы исключений также понадобится пометить атрибутом Бег1а11ззЬ1еАтьг1Ьпге. Благодаря этим трем общедоступным конструнторам, класс Буз Гею. Ех серг Топ очень полезен. Однако простую генерацию объектов типа Бузгев. Ехсертаоп всякий раз, когда в программе что-то идет не так, следует считать плохим дизайном. Вместо этого имеет смысл создать новый, более специфичный тип исключения, унаследовав его от Я уз сев.
Ехсерг1оп. Таким образом, тип исключения будет более выразительным в описании вызвавшей его проблемы. Еще лучше то, что производный класс может содержать данные, которые соответствуют причине генерации данного исключения. И помните, что в С№ все исключения должны наследоваться ст Бузгелг. Ехсерг1оп. Давайте посмотрим, что нужно сделать для эффективного определения пользовательских исключений.
Возьмем предыдущий пример Еглр1оуееРзгаЬзее. Предположим, что перед добавлением сотрудника в базу данных его данные нужно проверить на предмет достоверности. Если данные сотрудника по каким-то причинам не подойдут, метод АсЫ сгенерирует ис- Безопасность и обработка исключений 213 ключение типа Епр1оуееЧег111сасйопЕхсергтоп, Обратите внимание, что имя нового типа исключения заканчивается на Ехсергйоп. Выработать у себя такую привычку очень полезно, поскольку это общепринятое соглашение, позволяющее легко находить типы исключений внутри системы типов.
Зто также считается хорошим тоном в сообществе программистов на СМ. Посмотрим, как может выглядеть такое исключение: ив1по Яувгеко иягпс Буясек. Випг1ае. Бегта11явсгоп; (Бегза11яввге() ) риЬ11с с1аяв Еар1оуееЧеггтгсас1спЕхсерстоп: Ехсерс1сп риЬ1гс епиа Савве ( 1пга1гзЯЯИ, гпчв1гдв1гСЬРвге ) риЬ11с Епр1оуееЧег111свс1спЕхсергтсп( Савве геавоп ) :Ъаяе() ( СЬ1в.певясп = геавоп; ) риЬ11с Еар1оуееЧег111саг1спЕхсерсйсп( Савве геавоп, Ясг1пд вяд ) :Ьаяе( аяс ) ( ГЬ1я.пеьвоп = геввоп; риЬ11с Еар1суеесег111свгтопЕхсерсгоп( Саияе геаяоп, ясский пво, Ехсерг1оп копет ) :Ьаве( аяо, 1ппег ) ( Сптв.кеавоп = геаяспк ргогесгед Еар1оуееЧеггстсзггопЕхсерстоп( Яег1в11явсйоп1пто тпсо, Яггеза1пдсопгехс сопсехс :Ьвве( Боко, сопсехг ) ( ) риЬ11с Савве Ееаяоп ( Бег; рг1яасе век~ ) В методе Епр1оуееоагаЬаяе.
Адс( показан пример вызова Ча11даге на объекте епр. Зто черновой пример, где проверка должна завершиться неудачей, сгенерировав искзючение Епр1оуееЧег111саг1опЕхсергкоп. Пзавная цель этого примера — создание нового типа исключения. В будущем еще не раз придется убедиться в том, что простого создания нового типа исключения вполне достаточно для доставки дополнительной информации. В данном случае требовалось проиллюстрировать пример, где тип исключения несет в себе дополнительную информацию о причинах неудачи проверки, для чего было создано свойство Ееаяоп, связанное поле которого должно инициализироваться в конструкторе.
К тому же обратите внимание, что класс Епр1оуееЧег111сас1опЕхсерсйоп наследуется ог Яуясеп. Ехсергйоп. Поначалу существовало представление, что все определенные в .)ч)ЕТ Ггзгпеюог)г типы исключений должны наследоваться от класса Бувгеп. Ехсерс1оп, в то время как определяемые пользователями исключения — от Арр11сасзопЕхсерг1оп.














