Программирование на Visual C++. Архив рассылки
Шрифт:
Множественное наследование. В clr есть две новации. Одна – реализация множественного наследования для интерфейсов. По всей видимости, это расширение сделано с целью избавиться от QueryInterface. QueryInterface должен быть заменен на операцию приведения типов. С точки зрения идеологии красивое решение, но не приведет ли оно к проблемам интеграции с COM? Вторая новация связана с запретом множественного наследования. Множественное наследование наряду с шаблонами и переопределением операторов были C++. Похоже, времена меняются. Множественное наследование не запрещено в чистом C++. Но его использование ограничено в MC++. VB.Net и C# вообще не поддерживают множественного наследования, но об этом мы еще поговорим при рассмотрении этих языков.
Делегаты.
CLR-делегаты используются для привязки вызова метода объекта к переменной. Это гибрид указателей на функции в С или, точнее, на функции-члены в C++. Функционально делегаты похожи на интерфейсы с единственным методом, с тем отличием, что целевому типу нужно только иметь метод, чья сигнатура соответствует сигнатуре делегата.
Посмотрите на следующий пример:
Заметьте, что вместо интерфейса определяется простой тип-делегат. Заметьте ещё, что вызов перехватчика использует синтаксис, похожий на указатели функций С/C++. Разные языки VS.Net имеют различный синтаксис работы с делегатами, но внутренний механизм един.
Чтобы написать перехватчик MyClassEx, нужно просто реализовать метод, чья сигнатура соответствует сигнатуре делегата Hook:
Обратите внимание – MyHookEx не имеет явных ссылок на тип-делегат Hook. Вместо этого у него есть метод с сигнатурой, соответствующей сигнатуре Hook, что делает этот тип кандидатом на регистрацию в качестве обработчика для MyClassEx. Чтобы зарегистрировать обработчик, вам нужно только создать экземпляр нового делегата, основанного на типе-делегате Hook:
Обратите внимание на несколько необычный синтаксис инициализации делегата. Компилятор C# скрыто генерирует код инициализации нового объекта-делегата с маркером метаданных для означенного метода.
На таком же принципе построена система обработки событий. Но регистрация обработчика подразумевает возможность подключения нескольких обработчиков событий для одного источника. В C# такое подключение делается с помощью оператора «+=».
Полная поддержка аспектно-ориентированного программирования. MTS и COM+ представили массам аспектно– ориентированное программирование, позволив разработчикам переместить независимые от логики приложения аспекты из исходного кода в декларативные атрибуты. MTS и COM+ ввели также понятие как контекст для управления областью исполнения объекта. Контексты подразделяют процессы и содержат упорядоченную коллекцию именованных контекстных свойств, контролируемых атрибутами
класса наподобие Synchronization, ThreadingModel, Transaction и т.д. CLR продвигает эту концепцию дальше и значительно расчищает реализацию.В MTS и COM+ наборы атрибутов класса и свойств контекста были фиксированными. В CLR можно определить новый атрибут класса, вносящий новые свойства в контекст объекта. Это позволяет стороннему разработчику определять сервисы, поведение которых будет задаваться через атрибуты, контекстные свойства и перехват.
В COM+ объектные ссылки были ограничены контекстом, и для использования объектных ссылок в глобальных переменных нужна была Global Interface Table (GIT). В CLR областью действия объектных ссылок является AppDomain (эквивалент процесса в CLR), и объектные ссылки можно использовать в глобальных переменных без всякого маршалинга.
В COM+ все объекты прикреплены к контексту, в котором были инициализированы, и по умолчанию маршалятся в другие контексты по ссылке. В результате даже те объекты, которым не нужны сервисы типа транзакций или декларативной безопасности, оказываются замкнуты в конкретном контексте процесса. Чтобы избежать этого, разделяемые объекты часто агрегируют freethreaded-маршалер (FTM), делающий их контекстно-независимыми при вызове изнутри процесса, но маршалящий по значению за границы процесса. Объекты, требующие межпроцессного доступа через копию объекта, вместо proxy обычно реализуют IMarshal для обеспечения семантики маршалинга по значению.
В CLR по умолчанию используется маршалинг по значению между AppDomains и контекстная независимость внутри AppDomains, см. рисунок 1.
Рис. 1. Объект CLR
Это значит, что по умолчанию объект никогда не получит proxy. Вместо этого внутри исходного AppDomain-а доступ к объекту будет осуществляться напрямую, а доступ между AppDomain-ами производится путем копирования объекта. Как показано на рисунке 2, классы, унаследованные от System.MarshalByRefObject, контекстно-независимы внутри AppDomains, но маршалятся по ссылке между AppDomain-ами (грубый говоря, это эквивалент агрегирования FTM в COM+).
Рис. 2. MarshalByRefObject в CLR
Объекты, наследующие функциональность от System.ContextBoundObject, приколоты к контексту, в котором они инициализированы (см. рисунок 3), точно так же, как по умолчанию в COM+.
Рис. 3. ContextBoundObject в CLR
И все это доступно без явного кодирования, просто изменением базового класса.
Итак, наш небольшой анализ показывает, что ориентация Microsoft на COM заменяется ориентацией на CLR. Но остается вопрос, так что же, COM умер? По сути, COM жив и жалеет всех живых. Во-первых, у CLR пока нет собственных средств межмашинного взаимодействия. Такое взаимодействие осуществляется с помощью старого доброго COM. Во-вторых, большое количество современных продуктов целиком и полностью ориентировано на COM и ActiveX.
Но совместимость между COM и CLR далеко не стопроцентная. Это обусловлено различиями в архитектуре и неполной поддержкой со стороны самих средств разработки. Но CLR дает существенный выигрыш программистам, сейчас ориентированным на COM. Практически все аспекты модели программирования COM уцелели (интерфейсы, классы, атрибуты, контексты и т.д.). Однако CLR – это другая, лучшая модель компонентного программирования. Она упрощает межъязыковую интеграцию, позволяя расширять (путем наследования) функциональность классов созданных на других языках.