Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

 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 – красный.

Чтобы определить новые пользовательские атрибуты, следует создать новый класс, унаследовав его от System.Attribute, и реализовать в этом классе public-конструктор:

using System;

[ AttributeUsage(AttributeTargets.All) ]

public class ColorAttribute : Attribute {

 public String color;

 public ColorAttribute(string c) { color = c;}

Поделиться с друзьями: