Рейтинговые книги
Читем онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 110 111 112 113 114 115 116 117 118 ... 156

Единый стандарт обмена метаданными. Как уже говорилось раньше, информация о типах в COM передавалась в текстовой (IDL, заголовочные файлы) или в бинарной (TLB) форме. В CLR, напротив, информация о типах всегда передается в одной и той же документированной бинарной форме. Все работающие с CLR средства и компиляторы выдают и принимают метаданные в этом формате. Так, при определении набора интерфейсов разработчик может использовать свой любимый язык программирования и компилятор для создания описаний типов, вместо того, чтобы использовать один синтаксис (IDL) при описании типов и другой (например, C++ или Visual Basic) при их реализации.

Доступность метаданных во время исполнения. Из постулата единого формата метаданных вытекает доступность метаданных в runtime, даже если во время разработки метаданные доступны не были. Причем можно не только читать, но и писать метаданные (создавать новое описание). Это дает возможность создавать динамически расширяемые приложения, позволяющие использовать информацию о типах для подключения внешних модулей или динамического вызова методов и установки свойств. Одним словом предполагается, что такие сложные приложения, как контейнеры объектов (дизайнеры форм, менеджеры транзакций и т.п.) можно будет писать на любом языке программирования, даже на VB. Более того, описание, сделанное на одном языке, можно будет использовать в другом без каких либо дополнительных действий. Еще более того, можно будет наследовать классы одного языка от классов, описанных на другом языке.

Например, рассмотрим следующий COM IDL:

[ uuid(ABBAABBA-ABBA-ABBA-ABBA-ABBAABBAABBA) ]

library MyLib {

 importlib("stdole32.tlb");

 [ uuid(87653090-D0D0-D0D0-D0D0-18121962FADE) ]

 interface ICalculator : IUnknown {

  HRESULT Add([in] double n, [in, out] VARIANT_BOOL *round, [out] VARIANT_BOOL *overflow, [out, retval] double *sum);

 }

}

Эквивалентный тип CLR на C# (это новый язык программирования, который претендует стать основным языком VS.Net, о нем мы еще подробно поговорим позже) будет выглядеть так:

namespace MyLib {

 interface ICalculator {

  double Add(double n, ref bool round, out bool overflow);

 }

}

Если поместить это описание в файл, то его можно будет скомпилировать с помощью компилятора C#, следующей командной строкой:

csc.exe /t:library /out:mylib.dll mylib.cs

Полученное бинарное описание можно импортировать, например, в VB, используя ключ компилятора "/r":

vbc.exe /r:mylib.dll program.vb

CLR не снимает необходимости определения типов, он позволяет разработчику делать это на любом языке, совместимом с CLR.

CLR предоставляет библиотеку, позволяющую в runtime-е читать и/или создавать сборку, содержащую описание типов. Нижеприведенный листинг демонстрирует создание сборки, содержащей описание следующего интерфейса:

namespace MyLib {

 public interface ICalculator {

  double Add(double n, ref double round, out double overflow);

 }

}

Код, создающий сборку, реализован на C#, языке, похожем на C++ или Java. Мы надеемся, что у вас не возникнет проблем с пониманием кода:

using System;

using System.Reflection;

using System.Reflection.Emit;

public class emititf {

 // Точка входа программы (объектно-ориентированный аналог функции main в С/C++)

 public static int Main(String[] argv) {

  // Создаем новую сборку AssemblyBuilder ab = DefineNewAssembly();

  // Создаем определение нового интерфейса ICalculator внутри новой сборки

  TypeBuilder tb = DefineICalculator(ab);

  // Добавляем описание метода "Add" к описанию интерфейса

  ICalculator MethodBuilder method = DefineAddMethod(tb);

  // Добавляем описание параметров

  DefineAddParameters(method);

  // Создаем тип

  Type t = tb.CreateType();

  // Записываем сборку в файл "mylib.dll"

  ab.Save("mylib.dll");

  return 0;

 }

 // Создает сборку с именем "mylib"

 static AssemblyBuilder DefineNewAssembly() {

  // Новая сборка создается в рамках текущего AppDomain-а

  AppDomain current = AppDomain.CurrentDomain;

  // Новая сборка нуждается в имени. Назначаем ей не строгое имя!

  AssemblyName an = new AssemblyName();

  an.Name = "mylib";

  // DefineDynamicAssembly завершает работу по созданию сборки

  return current.DefineDynamicAssembly(an, AssemblyBuilderAccess.Save);

 }

 // Создает новое описание интерфейса с именем "MyLib.ICalculator"

 static TypeBuilder DefineICalculator(AssemblyBuilder ab) {

  // Все описания типов находятся в модуле, определенном для нашей сборки

  ModuleBuilder mb = ab.DefineDynamicModule("mylib.dll", "mylib.dll");

  // Все описания интерфейсов должны быть помечены как Interface и Abstract

  TypeAttributes attrs = TypeAttributes.Interface | TypeAttributes.Abstract;

  // public-интерфейсы должны быть также помечены как

  Public attrs |= TypeAttributes.Public;

  // DefineType завершает работу по созданию описания для интерфейса

  return mb.DefineType("MyLib.ICalculator", attrs);

 }

 // Создает новое описание методов "double Add(double, ref double, out double)"

 static MethodBuilder DefineAddMethod(TypeBuilder itf) {

  // Методы интерфейса должны быть помечены как abstract, virtual и public

  MethodAttributes attrs = MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual;

  // Метод определяется по имени и описанию (его параметрам)

  // Создаем описание возвращаемого значения

  Type resultType = typeof(double);

  // Создаем описание параметров

  Type[] paramTypes = new Type[] {

   typeof(double), Type.GetType("System.Boolean&"), Type.GetType("System.Boolean&")

  };

  // DefineMethod завершает работу по созданию описания метода

  return itf.DefineMethod("Add", attrs, resultType, paramTypes);

 }

 // Задает имя параметров и их последовательность

 static void DefineAddParameters(MethodBuilder method) {

  // 1-й и 2-й параметры не нуждаются в специальных атрибутах

  method.DefineParameter(1, ParameterAttributes.None, "n");

  method.DefineParameter(2, ParameterAttributes.None, "round");

  // Параметру 3 нужно задать флаг

  Out ParameterBuilder pb = method.DefineParameter(3, ParameterAttributes.Out, "overflow");

  // 3-му параметру также необходимо задать атрибут

  Interop.Out AddInteropOutAttribute(pb);

 }

 // Задает атрибут Interop.Out для параметра

 static void AddInteropOutAttribute(ParameterBuilder param) {

  // Конструкторы идентифицируют пользовательские атрибуты

  Type attrtype = typeof(System.Runtime.InteropServices.OutAttribute);

  ConstructorInfo outattrctor = attrtype.GetConstructors()[0];

  // CustomAttributeBuilder сериализует аргументы конструктора

  CustomAttributeBuilder outattr = new CustomAttributeBuilder(outattrctor, new object[0]);

  // Всю работу выполняет SetCustomAttribute

  param.SetCustomAttribute(outattr);

 }

}

Определение типа, сгенерированное этой программой, неотличимо от производимого компилятором C# (Visual Basic, C++, Perl, Python, или любого другого совместимого с CLR).

Метаданные обязательны. В com можно было определить на C++ частные интерфейсы, не описывая их в IDL или библиотеке типов. Это позволяло создать недокументированную лазейку в свой объект. В CLR это сделать не удастся.

В CLR все типы должны быть документированы через информацию о типах, включая private-типы (скрытых типов), не рассчитанные на внешнее использование. Для поддержки скрытых типов компонента метаданные CLR позволяют пометить типы (и их отдельные члены) как доступные только изнутри описываемой сборки. Например, следующий интерфейс виден только из сборки, в которой он определен:

internal interface IBob {

 void hibob();

}

Напротив, следующий интерфейс виден любой сборке:

public interface IBob {

 void hibob();

}

Метаданные полностью расширяемы. Информацию о типах com можно было расширить за счет пользовательских атрибутов. На практике это можно было сделать только через IDL, или прямой модификацией TLB. Пользовательские атрибуты в COM ассоциировали пару GUID/VARIANT с библиотекой, интерфейсом, CoClass-ом, методом, параметром, структурой или полем. Увы, VB и многие другие средства разработки не предоставляли путей задания или чтения пользовательских атрибутов, так что эта возможность бесполезна для большинства COM-разработчиков.

Информация о типах CLR расширяема из любого языка. Пользовательские атрибуты в CLR – это просто сериализованные вызовы конструктора. Разные языки имеют разный синтаксис для применения атрибутов. В C# можно просто вставить вызов конструктора в скобках, перед каким либо определением:

[ Color("Red") ]

class MyClass {}

В Visual Basic.NET можно вставить вызов конструктора в <>:

Class <Color("Red")>

MyClass

End Class

В любом случае метаданные будут указывать, что цвет MyClass – красный.

1 ... 110 111 112 113 114 115 116 117 118 ... 156
На этой странице вы можете бесплатно читать книгу Программирование на Visual C++. Архив рассылки - Алекс Jenter бесплатно.
Похожие на Программирование на Visual C++. Архив рассылки - Алекс Jenter книги

Оставить комментарий