Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 13
Текст из файла (страница 13)
Однако у разработчиков компилятора Са имеется козырь. Если следовать рекомендуемым соглашениям по именованию типов .НЕТ, с начальной заглавной буквой, то подобная ситуация никогда не возникнет. Вдобавок, если во время разработки приложения применяется анализатор кода Н(зиа! Б(иб(о или РхСор (автономная версия анализатора кода), данная проблема также никогда не появится. Эти правила и руководства подробно рассматриваются в книге Кжиштова Цвалина (Кшузг(о( Саайпа) и Брэда Абрамса (Втаб АЬгаглз) Ргаглеиог(г ()ез(дл Бабе(алея: Солчепболз, (б(огня, алб Ракегля Гог йеизаЫе .ГЧЕТ ЫЬгапея (Абб(яоп-УУея(еу Рго(езз(опа(, 2005 г.)', которую настоятельно рекомендуется прочитать. Преобразования типов Необходимость в преобразовании экземпляров одного типа в другой возникает очень часто.
В некоторых случаях компилятор выполняет такое преобразование неявно — когда значение одного типа присваивается переменной другого типа, и при этом не теряется точность и значение. В случае если точность может быть утеряна, требуется явное преобразование. Для ссылочных типов правила преобразования аналогичны правилам преобразования указателей в С++. Семантика преобразования типов подобна той, которая реализована в С++ и дача.
Явные преобразования выполняются с применением знакомого синтаксиса приведения, который все они унаследовали от языка С, те, тип, к которому нужно преобразовать. помещается в скобках перед преобразуемым типом: тпк бе1аи11уя1ие = 12345878! 1опо ча1ие = бегаи1СЧа1иег тпг япа11егуа1ие = (Ьпг) ча1ие; В этом коде приведение (Ьпс) должно бытьявным, поскольку размер 1пс меньше, чем 1опд. То есть существует возможность того,что значение типа 1опд не уместится в пространство, отведенное под Ьпс. Присваивание переменной с(егаи1ЬЧа1ие переменной ча1ие не требует приведения, поскольку 1опд имеет больше места для хранения, чем 1пс.
Если при преобразовании теряется значение, возможно, что эта операция сгенерирует исключение во время выполнения. Общее правило гласит, что неявные преобразования гарантированно никогда не сгенерируют исключений, в то время как явные — наоборот, могут. Язык СВ предоставляет средства для определения пользовательскик операций явного и неявного преобразования определенных пользователем типов к различным другим типам. Эта тема более детально раскрывается в главе 6. Требования исключений для встроенных операций преобразования применимы к операциям преобразования, определенных пользователем. В частности, операции неявных преобразований гарантированно никогда не генерируют исключений. Планируется к выходу. Разработка инбзраппруктпуры проектирования: соглашения, идиомы и шаблоны (ИД "Вильямс", 2010 г.). Обзор синтаксиса Са 49 Преобразования к ссылочным типам и обратно моделируют аналогичные операции в,)ача, а также операции преобразования между указателями в С++.
Например, ссылка на тип ОеггчебТуре может быть неявно преобразована к ссылке на тип ВаяеТуре, если Оег1чес[туре наследуется от ВавеТуре. Однако преобразование в обратном направлении должно осуществляться явно. К тому же явное приведение может сгенерировать исключение Буягеи. 1пча11ЗСавСЕхсерггоп во время выполнения программы, если СЬК не сможет выполнить такое преобразование. Ковариантность массивов Существует один тип неявного приведения, доступного в С(), которое реализовать в С++ не просто — главным образом, из-за семантики значений по умолчанию в С++. Массив одного ссылочного типа можно неявно преобразовывать в массив другого ссылочного типа до тех пор, пока целевой ссылочный тип допускает неявное преобразование от исходного ссылочного типа, и массивы имеют одинаковую размерность.
Это называется ковариантностью массивов. Например, следующее преобразование совершенно законно; РпЬ1гс с1вяя ЕпггуРогпС ( ягвггс чогб Мвтп() ( ясг1по[) паиев = пем ясгспп(4) 1 оЬ)есС[) оЬ3есСв = пвиеяк /! оператор с неявным преобразованием якгспч[) оггдгпв1ивиев = (ягг1пп[)) оЬ)ескя; l/ оператор с явным преобразованием Поскольку Буягет.яггспд наследуется от Бувгеи.ОЬ3есС и, следовательно, неявно преобразуем к БувСеи.ОЬ3есС.такое неявное преобразование массива яггспу по имени навея в массив оЬ3есС по имени оЬ3ес я возможно.
Однако, как показано, для обратного преобразования необходимо явное приведение, которое может сгенерировать исключение в случае неудачи. Имейте в виду, что неявные преобразования аргументов могут происходить при вызове метода, если аргументы должны быть преобразованы для соответствия типам параметров. Если выполнить преобразование неявно не удается, придется выполнить явное приведение.
Упаковыва)ощее преобразование И, наконец, есть еще один распространенный вид преобразования — упаковывающее преобразование [Ьоюпя сопчегв(оп). Такое преобразование требуется, когда необходимо передать тип значения как параметр ссылочного типа в метод или же присвоить его переменной ссылочного типа. При этом происходит динамическое размещение в куче объекта, содержащего поле типа значения. Значение затем копируется в зто поле. Такого рода упаковка подробно рассматривается в главе 4. Упаковка демонстрируется в следующем коде: рпЬ11с с1яяя ЕпггуРогпС ( ягвггс чо1б Мата() ( гпС еир1оуее10 = 303; оЬ3есг Ьохеб10 = еир1оуее10; етр1оуее10 =.
4041 гпС пппохеб10 = (1пг) Ьохеа10; Буягет.Сопяо1е.кгске11пе( еир1оуее10.тоЯСгспч() ); Яуягеи.сопяо1е.кгсге11пе( пппохеа10.тояггспч() ) ) 50 Глава 3 В точке, где переменной Ьохеб1Р типа ОЬ» есг присваивается значение переменной евр1оуее1Р типа Ьпг,происходит упаковка. Создается объект, базирующийся в куче, и в него копируется значение евр1оуее10. Это заполняет разрыв между мирами типов значений и ссылочньгх типов внутри СЬВ. Объект Ьохеб1Р в действительности содержит копию значения евр1оуее10. Этот факт демонстрируется за счет изменения первоначального значения евр1оуее1Р после операции упаковки.
Перед выводом на консоль производится распаковка и копирование значения, содержащегося в объекте, из кучи обратно в другой 1пг в стеке. Распаковка в С№ требует явного приведения. Операции аз и ~в Поскольку явное преобразование может потерпеть неудачу с генерацией исключения, бывает так. что необходимо проверить тип переменной беэ выполнения приведения и наблюдения, получится оно или нет. Проверка типа через приведение утомительна н неэффективна. к тому же исключения дорого обходятся во время выполнения. По этой причине в С№ предусмотрены операции, которые приходят на помощь в таких ситуациях и применение которых гарантированно не приведет к исключениям: 15 ° аз Операция Ья дает в результате булевское значение, говорящее о том, можно ли преобразовать данное выражение в указанный тип, как с помощью преобразования ссылки, так и посредством операл;кй упаковки и распаковки.
Например, рассмотрим следующий код: пзтпч Яуясеяк РпЬ11с с1яяя Епггуаоапс ( ясястс чотб Мягп() ( Ясг1пд бегбчебОЬ» = "Рппялу"; ОЬ»есс ЬязеОЬ»1 = пен ОЬ»ест()? ОЬ»ест ЬязеоЬ»2 = бегтчебОЬ»; Сопзо1е.нгтсеЬЬпе( "ЬяяеОЬ»2 (О) Ясг1ПЯ", ЬаяеОЬ»2 Ья Ясг1пч ? "является": "не является" )) Сопяо1е.кгтсеЬЬпе( "ЪяяеОЬ»1 (О) Ясгтпд", ЬязеОЬ»1 Ья астапов ? "является": "не является" ); Сопяо1е.нгтсеЬ1пе( "бегтчебОЬ» (О) ОЬ»есс", бегтчебОЬ» Ьз ОЬ»есс ? "является": "не является" ) Ьпп » = 123) оЬ»есс Ъохеб = ») оЬ»есс оЬ» = пен ОЬ»есг О ? Сопяо1е.кгтсеъапе( "Ьохеб (О) Ьпс", Ьохеб Ьз Ьпс ? "является": "не является" )~ Сопяо1е Иг»сеътпе( "оЬ» (О) Ьпс", оЬ» 1я Ьпс ? "является": "не является" ); Сопяо1е.кгтсеЬЬпе( "Ъохеб (О) Яузсев.Ня1петуре", Ьохеб Ья чя1иетуре ? "является": "не является" ); Вывод этого кода будет таким: ЬяяеОЬ»2 является Ясг1пя ЬяяеОЬ»1 не является Ягг1пд бегбчебОЬ» является ОЬ»ест Ьохеб является 1пг оЬ» не является Ьпс Ьохеб является Яузсев.Чя1петуре Обзор синтаксиса О№ 51 Как уже упоминалось, операция ).
з принимает во внимание только преобразования ссылок. Зто значит, что она не может проверять определенные пользователем преобразования, имеющиеся в типах. Операция аз подобна Тз за исключением того, что она возвращает ссылку на целевой тип. Поскольку гарантируется, что она никогда не сгенерируст исключения. то если данное преобразование невозможно, просто возвращается пп11-ссылка. Подобно Тз, операция аз принимает во внимание только преобразования ссылок или преобразования с упаковкой/распаковкой.
Например. взгляните на следующий код; пзтпд Яузгеки рпЬ11с с1азз ВазеТуре () риЬ11с с1азз ПеггчебТуре: ВазеТуре () риЬ11с с1азз Епггуротпг ( зсагас чоаб Матп() ( РеггчебТуре бег1чебОЬЗ = пен ОегтчебТуре(); ВазеТуре ЬазеОЬЗ1 = пен ВазеТуре()т ВазеТуре ЬззеОЬЗ2 = бег1чебОЬЗ; ОегачебТуре бегтчебОЬ)2 = ЬазеОЬЗ2 зз бегтчебТуре; 11( бегтчебОЬЗ2 != пп11 ) ( Сопзо1е.кгтгеьгпе( "Преобразование успешно" )т ) е1зе ( Сопзо1е.игтгеьтпе( "Преобразование не удалось" )т беггчебОЬЗ2 = ЬазеОЬЗ1 аз Пег1чебТуре; 11( бег1чебОЬЗ2 != пп11 ) ( Сопзо1е.иг1сеьтпе( "Преобразование успешно" )~ ) е1зе ( Сопзо1е.иг1сеь1пе( "Преобразование не удалось" ); ) ВазеТуре ЬазеОЬЗЗ = беггчедОЬЗ аз ВазеТурет г№( ЬазеОЬЗЗ != пи11 ) ( сопзо1е.игтгеьгпе( "преобразование успешно" ); ) е1зе ( Сопзо1е.вг1ге11пе( "Преобразование не удалось" ); ) ) Вывод этого кода будет таким: Преобразование успешно Преобразование не удалось Преобразование успешно Иногда требуется проверить, относится ли переменная к определенному типу, и если да, то выполнить какую-то операцию над нужным типом.
Проверить переменную на принадлежность к типу можно с использованием операции Тз, а затем, если она вернет ггпе, привести переменную к этому типу. Однако это будет не эффективно. Более удачный подход заключается в том, чтобы следовать идиоме применения операции аз для получения ссылки на переменную с нужным типом, а затем проверить ее на неравенство пб11, что будет означать успешность преобразования. Таким образом, потребуется выполнить только одну операцию просмотра типа вместо двух. Обобщения Поддержка обобщений (яепепсз) — одно из наиболее впечатляющих нововведений в языке С№. С помощью синтаксиса обобщений можно определить тип, зависящий от другого типа, который нс специфицирован в точке определения, а вместо этого опреде- 52 Глава 3 лен в точке использования обобщенного типа. Для примера рассмотрим некоторый тип коллекции.











