Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 9
Текст из файла (страница 9)
Не11), когда замена совместно используемой ПЫ библиотеки ее новой версией приводит к нарушению работы приложений, пользующихся старой версией этой библиотеки. Если вы — ветеран, которому пришлось разрабатывать программное обеспечение для Ж1пдонэ в течение последних 15 лет или около того, то вы определенно испытали это на 34 Глава 2 себе. В СЬН множество версий одной и той же сборки могут мирно сосуществовать иа одной и той же машине без каких-либо конфликтов между собой. Более того, приложения по умолчанию могут выбирать использоваиие наиболее свежей версии, имеющейся иа машине, или же указывать точную версию, применяя политику версий в своих коифигурациоииых файлах.
На заметку! Загрузка сборок и работа с версиями — исключительно сложная тема, и ее освещение выходит за рамки этой книги. Пред тем, как загрузить сборку, загрузчик использует различные эвристические приемы для определения того, какую версию следует загрузить. Определив версию, он передает эту информацию вниз — низкоуровневому методу загрузки сборок. Подробнее о загрузке сборок читайте в книге Дона Бокса и Криса Селлса Еввепба! .ИЕТ, Уо!игле 1: Тле Сотгпоп 1апдиаде Яоп№гпе !Або!воп-УУев!еу Рго!езз!опа!, 2002 г!. Метаданные Давайте внимательнее рассмотрим пример "Не11о тдог16!" в листинге 1.1 и сравним его с тем, что вы могли бы делать, если пришли из мира С++. Для начала обратите виимание, что здесь иет никаких включений заголовков.
Причина в том, что С№ в этом ие нуждается. Взамен используется нечто более надежное и информативное, а именно— метадаииые. За счет применения метаданных управляемые модули являются самоописательиыми. В мире С++ для подключения библиотеки к приложению нужны две вещи: статическая библиотека или РЬЬ и обычно заголовочный файл. Поскольку оии существуют как две отдельные сущности, которые должны трактоваться как одно целое, вполне возможно, что заголовочный файл окажется ие соответствующим библиотеке, если ие проявить должную осторожиость.
Это может привести к неприятностям. Управляемые модули, с другой стороны, содержат всю необходимую информацию внутри метадаииых. находящихся в самом модуле. Единицей повторного использования в управляемом мире является сборка, и сборки могут состоять из множества модулей.
Таким образом, сборка, фактически, самодостаточна. Метадаииые также являются расширяемыми, что позволяет определять новые типы и атрибуты, которые могут содержаться в метаданных. И в завершение следует отметить, что доступ к метадаииым воэможеи во время выполнения. Например, во время выполнения можно пройти по всем полям произвольиого типа класса, ие зная его объявления заранее, перед компиляцией. Сообразительный читатель поймет, что зто открывает возможность генерации целых программ и типов во время выполнения, что также совершенно невозможно в родном С++, если только ие встроить в приложение полный компилятор С++.
Метадаииые — это расширяемый формат описания содержимого сборок. К тому же если зто ие слишком дорого, то можно определять собственные специальные "атрибуты", которые легко включаются в метадаииые типа. В мире управляемого кода почти любая сущность программы с типом может иметь присоединенные к ией метадаииые, включая классы, методы. параметры, возвращаемые значения. сборки и т.д. Специальные атрибуты можно определить, унаследовав их от класса Бузкеа. АССг1Ьцке, а затем легко ассоциировать экземпляр специального атрибута почти с любой сущностью в сборке. С помощью метаданных можно получать доступ и исследовать определения типов и присоединенные к иим атрибуты.
Метадаииые могут сообщить о том, поддерживает ли определенный класс объекта конкретный метод, прежде чем пытаться вызвать его, либо порожден ли данный класс от какого-то другого. Процесс просмотра метаданных иазывается редглексией. Обычно рефлексия типов в сборке начинается с объекта Яуэсегл. Туре. С№ и Сбй 35 Получить один из этих экземпляров типов можно с помощью ключевого слова С№ Суреог, вызова Зузгеа. АззеглЬ1у. Сегтуре () или нескольких других способов.
В общем случае ключевое слово суреог более эффективно, потому что вычисляется во время компиляции, в то время как метод Сегтуре (), хотя и является более гибким, посколъку ему можно передавать произвольную строку, запускается во время выполнения. После получения объекта типа можно определить, является ли он классом. интерфейсом, структурой и т.п., какие методы у него есть, а также количество и типы содержащихся вием полей.
На заметку! Чтобы пояснить, зачем нужны метаданные, следует отметить, что в технологии СОМ/ ОСОМ используются несколько другие приемы. Если вы когда-нибудь создавали компоненты СОМ, то должны быть знакомы с 10Ь ()п!ег(асе Оевспр!юп (лпдцаде — язык описания интерфейсов), который представляет собой независимый от платформы язык описания интерфейсов и компонентов. Обычно вы предоставляете своему заказчику СОМ-компонент, упакованный в ОЬЬ-библиотеку или исполняемую программу, вместе с 10(.-описанием. Это описание служит той же цели, что и заголовочный файл для библиотек С++ или документация, сопровождающая ОЬЬ-библиотеку.
Обычно 10Ь-описание прогоняется через компилятор!ОЬ который генерирует "родной" код для последующего с ним взаимодействия. Библиотека типов (Туре Вбгагу — ТЕВ) служит почти той же цели, что 10Ь, но имеет двоичный формат, который обычно потребляют высокоуровневые языки вроде Ч1зца) Ваз)с. К сожалению, ЕОЬ и ТЕВ не полностью перекрывают друг друга. Некоторые вещи могут быть описаны на 10Ь, но не в ТЬВ, и наоборот. Поскольку сборки являются самоописательными, единственное, что нужно компилятору С№ для разрешения использования типов — это список сборок, на которые ссылается текущая, чтобы скомпилировать и построить программу.
Имея такой список, для разрешения зависимостей компилятор может обращаться к мегаданным, содержащимся внутри сборок. Это прекрасная система, и она исключает некоторые чреватые ошибнами детали из процесса кодирования С№. В управляемом мире вам больше не нужно заботиться о дополнительном багаже в виде заголовочных файлов или файлов П)Ь. Правда, нельзя утверждать, что больше не понадобится предоставлять и документацию, потому что документация полезна всегда. Но, имея сборку, вы получаете полноценно упакованную сущность, содержащую и код, и описания, необходимые для ее использования. Если сборка состоит иэ единственного файла, как чаще всего и бывает, то этот файл содержит все необходимое для того, чтобы использовать код, находящийся в этой сборке.
Совместимость между языками Поскольку сборки свмоописательны и содержат в себе переносимый код 1Ь, их легко разделять между многими языками. Наконец-то появилось жизнеспособное решение для построения сложных систем, в которых одна часть компонентов кодируется на одном языке, а другая — на другом. Например, при разработке сложной системы для инженерного анализа группа разработчиков на С№ может заниматься кодированием инфраструктуры системы, а группа инженеров — созданием математических компонентов. Многие инженеры все еще программируют на таком языке, как Рог!гап. Это нормально, потому что доступны компиляторы РЬг1гап, генерирующие 1Ь и создающие управляемые сборки. То есть каждая группа разработчиков может применять язык, более естественный для группы и предметной области.
которой она занимается. Метаданные очень важны при таком разделении. Формат метаданных полностью описан в книге Джима Миллера [д!гп МШег] и Сьюзанн Рэгсдейл (Вцвапп Наязба)е) Т)м Сопнпоп Ьапдиаде 1г№голггис!иге Аппоакег( Э!агк(агк( (А<И!зоп-ТЧез1еу Ртоуевв1опа1, 2003 г). 36 Глава 2 Чтобы лучше понять С1.К, генерацию и применение метаданных, рекомендуется также ознакомиться с документацией по стандарту СЫ Есша~. Резюме В настоящей главе кратко рассматривалась компиляция, упаковка и выполнение кода С№. Было показано, как ЛТ-компиляция может конкурировать с традиционно скомпилированными приложениями в плане производительности.
Одним из требований для оптимизации ЛТ-компиляции является выразительный и расширяемый механизм типов, который может быть понятен компилятору. При упаковке 1Ь в самодокументированные сборки среда СЬК и компилятор ЛТ имеют полную информацию, которая нужна им для управления выполнением кода. Сборку можно загружать явно по требованию, указывая либо строгое, либо частичное ее имя. Сборки позволяют запускать рааличные версии кода, избегая ситуации "ада ОЬЬ" и также предоставляя базу для разработки и разделения компонентов между языками. В следующей главе вы ознакомитесь с синтаксисом языка С№.
Поскольку для раскрытия всех его деталей места не хватит, я рекомендую вам также обратиться к спецификации языка С№. В документе Еста-335 описан стандарт Есгла СЫ, а в документе Есша-334 — язык С№ (оба документа доступны по адресу как. есаа-гссегсастопа1. огд).
Кроме того, в стандарте 1ЗО/!ЕС23271 рассматривается инфраструктура СЫ, а в 1БО/1ЕС23270 — язык С№ (стандарты 1ЗО находятся на сайге зкк. №зо. огч]. Однако стандарты Есша обычно более актуальные, к тому же доступны для бесплатной загрузки. ГЛАВА 3 Обзор синтаксиса СИ в этой главе вы ознакомитесь с синтаксисом языка С№. Предполагается, что вы уже имеете некоторый опыт работы в С++ или дача, потому что С№ разделяет сходный с ними синтаксис. Это не случайно.
Проектировщики С№ сознательно решили использовать знания тех разработчиков, которые уже имели дело с С++ и Вача — доминирующими языками в мире объектно-ориентированной разработки программного обеспечения. Нюансы и отличия, присущие языку С№, будут отмечаться специально. Если вы знакомы с С++ или дача, то с синтаксисом С№ почувствуете себя как дома. СФ вЂ” строго типизированный язык Подобно С++ и дача. С№ является строго типизированным языком, а это означает, что каждая переменная и экземпляр объекта в системе относятся к четко определенному типу.
Это позволяет компилятору проверять операции, которые вы пытаетесь выполнить с переменными нли экземплярами объектов. Например, предположим, что имеется метод. вычисляющий среднее значение из двух целых чисел и возвращающий результат. Такой метод С№ можно объявить следующим образом: боиЬ1е Совриселчо( 1пс рзгзв1, ьпс рагав2 ) ( гееигп (рзгав1 + рзгав2) у 2.0) ) Приведенный код говорит компилятору, что этот метод принимает два целых числа и возвращает число с плавающей точкой двойной точности (г(оиЬ1е).















