Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 123
Текст из файла (страница 123)
Каки в случае с яуясев.Сопуегс,методы 1СопуегсаЬ1е здесь не перечисляяются, хотя их и не так много. Загляните в документацию МЯЛ. Для преобразования в каждый встроенный тип предусмотрено по одному методу. Вдобавок Сопнегг использует универсальный метод 1СопуегсаЬ1е. ТоТуре для преобразования одного пользовательского типа в другой пользовательский тип. К тому же методы 1СопуегсаЬ1е принимают поставщик формат.
чтобы можно было указать методу преобразования информацию о культуре. Вспомните, что при реализации интерфейса потребуется предоставить реализации всех его методов. Однако если для объекта конкретное преобразование не имеет смысла, то в реализации соответствующего метода можно сгенерировать исключение 1пуе11п(Саяскхсер11оп. Естественно, реализация наверняка будет генерировать исключение внутри 1сопуег11Ь1е.
тотуре для любого типа, преобразование к которому не поддерживается. И напоследок: может показаться, что существуег несколько способов преобразования одного типа в другой в С№, и так оно и есть. Однако главное эмпирическое правило заключается в том, что когда простое приведение не работает, нужно полагаться на Яуясев. Сопуегс. Более того, пользовательские объекты вроде класса Совр1есновЬег доляцпы реализовать 1СопуегтеЬ1е, чтобы иметь возможность работать в сочетании с классом Яуясев. Сопуегс.
б поисках канонических форм С№ 459 На заметку) Язык С№ предлагает операции преобразования, позволяющие делать по сути то же самое, что и реализация ТсопчеггаЬ1е. Однако явные и неявные операции преобразования С№ не являются совместимыми с СЬЗ. Поэтому не каждый язык, потребляющий ваш код С№, сможет вызывать их для выполнения преобразований.
При выполнении преобразований не рекомендуется полагаться исключительно на них. Конечно, если проект разработан только на языках . МЕТ, поддерживающих операции преобразования, то их можно свободно испольэовать, но при этом также рекомендуется поддерживать ТсопнегсаЬ1е. В .ХЕТ Ргагпетчог)г доступен еще один тип механизма преобразования, который работает через Бузгет. сопропепгмоое1. Туресоптеггег.
Это еще один конвертер, внешний по отношению к классу преобразуемого экземпляра, как и еузгеи.сопчегс. ПрЕИМущЕСтВО ИСПОЛЬЗОВаНИя ТурЕСОПтгЕГГЕГ СОСтОИт В тОМ, ЧтО ЕГО МОЖНО ПРИМЕ- нять как во время проектирования, в 1ПЕ-среде, так и во время выполнения. Сначала для класса создается собственный специальный тип конвертера, унаследованный от ТуреСопчеггег, после чего новый тип конвертера ассоциируется с классом через атрибут ТуреСоптегсегдсгг1Ьцге. Во время проектирования 1ПЕ-среда может просмотреть метаданные этого типа и на основании информации, почерпнутой оттуда, создать экземпляр типа конвертера. Таким образом, 1ПЕ-среда может преобразовать тип в нужное представление и обратно, подходящее для использования.
Детали создания наследников ТуреСопчеггег здесь не рассматриваются. Дополнительную информацию можно найти в разделе "Оепегайгег) Туре Соптегз1оп" документации МХОМ. Всегда отдавайте предпочтение безопасности типов Как известно, С№ — строго типизированный язык.
Строго типизированный язык и его компилятор формируют динамический дуэт, способный выявлять ошибки до их проявления. Несмотря на то что каждый объект в управляемом мире унаследован от Еузсем. ОЬ1есщ будет очень плохой идеей трактовать каждый объект обобщенно, через ссылку на Еузсеп. СЬ) ест. Одной из причин является эффективность; например, если нужно сопровождать коллекцию объектов Емр1оуее через ссылки на Еуэсев.ОЬ)ест, то всегда придется приводить их экземпляры к типу Етр1оуее, прежде чем можно будет вызвать его метод класса Еча1цаге.
Проблема значительно усугубляется, когда дело касается типов значений, поскольку в этом случае требуются излишние операции упаковки, генерируемые в коде П.. Тема неэффективности упаковки еще будет затрагиваться в следующих разделах, посвященных типам значений. Самая большая проблема со всеми этими приведениями при работе со ссылочными типами проявляется тогда, когда приведение завершается неудачей и генерируется исключение. Применяя строгие типы, можно перехватывать эти проблемьг и справляться с ними еще на этапе компиляции. Другая наглядная причина отдать предпочтение использованию строгих типов связана с перехватом ошибок.
Рассмотрим случай реализации интерфейсов, таких как 1С1опеаЬ1е. Обратите внимание, что метод С1опе возвращает экземпляр типа ОЬ) ест. Ясно, что это делается для того, чтобы интерфейс мог работать со всеми типами. Однако за это приходится платить определенную цену. И С++, и С№ — строго типизированные языки. Каждая переменная объявляется со своим типом. Это обеспечивает безопасность типов, на страже которой стоит компилятор, помогая избегать ошибок. Например. он предотвращает присванвание экземпляру класса АРР1е значение экземпляра класса мол хеуигепсь. Однако с№ (и с++) позволяет работать в менее безопасной к типам манере.
На каждый объект можно ссылаться через тип СЬ) ест. Однако в этом случае полностью отбрасывается вся безопасность типов, и тогда компилятор позволяет выполнять присваивание экземпляру типа Арр1е значение экземпляра класса Мопхеунгепсн — до тех пор. пока обе ссылки имеют тип ОЬ) есс. 460 Глаза! 3 К сожалению, несмотря на то, что такой код компилируется.
есть риск получить ошибку времени выполнения, когда СЬК станет выполнять этот код. Поэтому чем больше используются средства контроля безопасности типов компилятора, тем больше ошибок можно обнаружить во время компиляции, а перехват ошибок на этапе компиляции всегда более желателен, чем их обнаружение во время выполнения. Давайте присмотримся внимательней к аспекту эффективности этой проблемы. Обобщенная трактовка объектов обычно наносит ущерб эффективности во время выполнения, когда приходится осуществлять приведение к действительному типу.
Когда речь идет об управляемых ссылочных типах С№, в действительности этот ущерб эффективности очень невелик, если только не делать это много раз в цикле. В некоторых ситуациях компилятор С№ генерирует намного более эффективный код, если предложить ему безопасную в отношении типов реализацию хорошо определенного метода. Рассмотрим типичный оператор Гогеасп на С№: гогеасп( Евр1оуее евр 1п со11ессгоп ) ( l/ Делать что-то ) Здесь все достаточно просто: код проходит циклом по всем элементам со11есг1оп.
Внутри тела оператора гогеасп переменная евр типа Евр1оуее ссылается на текущий элемент коллекции во время итерации. Одно из правил, устанавливаемым компилятором С№ для коллекций, гласит, что они должны реализовать общедоступный метод яеГЕпивегапог, который возвращает тип, используемый для перечисления элементов коллекции.
Этот метод обычно реализован как результат того, что тип коллекции реализует интерфейс 1ЕпивегаЬ1е, и часто возвращает прямой итератор на коллекции содержащихся объектов'. Одно из правил для типа перечислителя состоит в том, что он должен реализовать общедоступное свойство по имени Сиггепс, которое позволяет получить доступ к текущему элементу. Это свойство — часть интерфейса 1Епивегзсог; однако обратите внимание, что типом 1епивегагог.сиггепг является яувгев. ОЬ1есг. Отсюда вытекает другое правило, касающееся оператора 1огеасЬ.
Оно устанавливает. что тнп объекта 1епивегзсог. сиггепг — реальный тип объекта — должен быть неявно приводимым к типу итератора в операторе гогезсЬ; таким типом в данном случае является Евр1 оуее. Если перечислитель коллекции типизирует свое свойство Сиггепп как Я у в сев. ОЬ я есг, компилятор должен всегда выполнять приведение к типу евр1оуее. Однако несложно заметить, что компилятор может генерировать более эффективный код, если свойство Сиггепс относится к типу Евр1оуее. Итак, что же можно предпринять для исправления этой ситуации в мире С№? В сущности.
каждый раз, когда реализуется интерфейс, содержащий методы с безтиповыми возвращаемыми значениями, следует рассмотреть возможность явной реализации интерфейса, чтобы скрыть эти методы от общедоступного контракта класса, и в то же время реализовать их более безопасные к типам версии как часть упомянутого контракта. Давайте взглянем на пример использования интерфейса 1Епивегасог: ив1пч Яувпепп ив1пя яувгев.Со11есггопв; риЬ1№с с1азв Евр1оуее ( риЬ11с погд Епа1иапе О ( Сопво1е.иг1пеъ1пе( "Проверка Евр1оуее..." ) Здесь используется слово часпю, поскольку итераторы могут быть обратными.
В главе 9 было показано, квк создавать обратные и двунаправленные атераторы, реализующие гзпвпегапог. Е поисках канонических форм С№ 4Б1 риЬ1гс с1авв Хогнуогсекпивегатог: 1Епиветатог ( риЫгс ХоткготсеЕпивегаког( Аггауь№вт евр1оуеея ) СЫя.епивегатог = евр1оуеея.оеткпивегакот()к ) риЬ1гс Евр1оуее Ситтепк ( сег ( гетигп (Евр1оуее) епиветаког.ситтептк ) оЬ)ест 1Епивегаког.ситтепк ( сес ( гетигп епиветатот.Сиггептх ) ) риЬ1гс Ьоо1 Моиенехи О ( гетигп епиветатот.ноиенехс() риЫЕс ио1б Неяет() ( епивегаког.певек О / ) рг1иате 1Епивегаиот епиветатот1 риЬ1гс с1авв Иогнготсе: 1ЕпиветаЫе ( риЬ1га Иогкгогсе () ( евр1оуеев = пеи Лггауьквк О к // Добавить сотрудника в целях демонстрации.










