Отражение и универсальные типы

С точки зрения отражения разница между универсальным и обычным типом заключается в том, что универсальный тип связан с набором параметров типа (если это определение универсального типа) или с аргументами типа (если это сконструированный тип). Тем же отличается и универсальный метод от обычного.

Есть два ключевых момента, позволяющих понять, как в отражении обрабатываются универсальные типы и методы:

  • Параметры типов для определений универсальных типов и определений универсальных методов представлены экземплярами класса Type.

    ПримечаниеПримечание

    Поведение многих типов и методов класса Type отличается, если объект Type представляет параметр универсального типа.Эти различия документируются в темах, посвященных конкретным свойствам и методам.Примеры см. в разделах IsAutoClass и DeclaringType.В дополнение к этому некоторые члены являются допустимыми только в том случае, если объект Type представляет параметр универсального типа.Например, см. GetGenericTypeDefinition.

  • Если экземпляр класса Type представляет универсальный тип, он содержит массив типов, которые представляют параметры типа (для определений универсальных типов) или аргументы типов (для сконструированных типов). Это также справедливо для экземпляра класса MethodInfo, который представляет универсальный метод.

Отражение содержит методы классов Type и MethodInfo, которые позволяют получить доступ к массиву параметров типа и определить, представляет ли экземпляр класса Type параметр типа или фактический тип.

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

В следующем ниже обсуждении предполагается определенное знакомство с терминологией универсальных шаблонов, например знание того, в чем состоит отличие между параметрами типа и аргументами типа, а также открытыми и закрытыми сконструированными типами. Дополнительные сведения см. в разделе Универсальные шаблоны в платформе .NET Framework.

Этот обзор содержит следующие подразделы:

  • Универсальный тип или универсальный метод

  • Создание закрытых универсальных типов

  • Изучение аргументов типа и параметров типа

  • Инварианты

  • Связанные разделы

Универсальный тип или универсальный метод

При использовании отражения для изучения неизвестного типа, представленного экземпляром класса Type, следует использовать свойство IsGenericType, которое позволяет определить, является ли неизвестный тип универсальным. Если тип является универсальным, это свойство возвращает значение true. Аналогичным образом при изучении неизвестного метода, представленного экземпляром класса MethodInfo, для определения того, является ли этот метод универсальным, следует использовать свойство IsGenericMethod.

Наличие определения универсального типа или метода

Свойство IsGenericTypeDefinition используется для определения того, представляет ли объект Type определение универсального типа, а метод IsGenericMethodDefinition — для определения того, представляет ли объект MethodInfo определение универсального метода.

Определения универсальных типов и методов являются шаблонами, на основе которых создаются типы, поддерживающие создание экземпляров. Универсальные типы в библиотеке классов .NET Framework, например Dictionary<TKey, TValue>, являются определениями универсальных типов.

Каким является тип или метод — открытым или закрытым

Универсальный тип или метод является закрытым, если все его параметры типа были заменены типами, в том числе все параметры типа для всех инкапсулирующих типов, были заменены типами, допускающими создание экземпляра. Если универсальный тип является закрытым, допускается только создание экземпляра на его основе. Если тип является открытым, свойство Type.ContainsGenericParameters возвращает значение true. Для методов та же самая функция выполняется методом MethodInfo.ContainsGenericParameters.

К началу

Создание закрытых универсальных типов

После получения определения универсального типа или метода следует при помощи метода MakeGenericType создать закрытый универсальный тип либо при помощи метода MakeGenericMethod – объект MethodInfo для закрытого универсального метода.

Получение определения универсального типа или метода

При наличии открытого универсального типа или метода, который не является определением универсального типа или метода нельзя создавать экземпляры такого типа или метода, а также указывать отсутствующие параметры типа. Необходимо иметь определение универсального типа или метода. Для получения определения универсального типа или метода GetGenericMethodDefinition используется метод GetGenericTypeDefinition.

Например, если при наличии объекта Type, представляющего тип Dictionary<int, string> (Dictionary(Of Integer, String) в Visual Basic) нужно создать тип Dictionary<string, MyClass>, можно при помощи метода GetGenericTypeDefinition получить объект Type, представляющий тип Dictionary<TKey, TValue>, а затем воспользоваться методом MakeGenericType для создания объекта Type, представляющий тип Dictionary<int, MyClass>.

Пример открытого универсального типа, который не является универсальным типом, см. в разделе "Параметр типа или аргумент типа" ниже в этой теме.

К началу

Изучение аргументов типа и параметров типа

Для получения массива объектов Type, которые представляют параметры типа или аргументы типа для универсального типа, следует воспользоваться методом Type.GetGenericArguments, а для выполнения тех же действий в отношении универсального метода — методом MethodInfo.GetGenericArguments.

Если станет понятно, что объект Type представляет параметр типа, есть много других дополнительных вопросов, на которые можно ответить при помощи отражения. Можно определить источник этого параметра типа, его положения и его ограничения.

Параметр типа или аргумент типа

Чтобы определить, является ли конкретный элемент массива параметром типа или аргументом типа, следует использовать свойство IsGenericParameter. Если элемент является параметром типа, свойство IsGenericParameter имеет значение true.

Универсальный тип может быть открытым, не являясь определением универсального типа. В таком случае он представляет собой набор аргументов типа и параметров типа. Так, в следующем параметре класс D является производным от типа, созданного путем замены первым параметром типа класса D вторым параметром типа класса B.

class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
    Inherits B(Of Integer, V)
End Class
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};

В результате получения объекта Type, представляющего класс D<V, W>, и использования свойства BaseType для получения его базового типа, итоговый тип type B<int, V> является открытым, однако при этом не представляет собой определение универсального типа.

Источник универсального параметра

Параметр универсального типа может быть получен из изучаемого типа, инкапсулирующего типа или из универсального метода. Источник параметра универсального типа можно определить следующим образом:

  • Во-первых, можно воспользоваться свойством DeclaringMethod, чтобы определить, получен ли параметр типа из универсального метода. Если значение свойства не является пустой ссылкой (Nothing в Visual Basic), источник является универсальным методом.

  • Если источник не является универсальным методом, для определения универсального типа, которому принадлежит параметр универсального типа, следует использовать свойство DeclaringType.

Если параметр типа относится к универсальному методу, свойство DeclaringType возвращает тип, объявивший универсальный метод, который является несоответствующим.

Положение универсального параметра

Иногда необходимо определить положение параметра типа в списке параметров типа объявившего класса. Например, предположим, что есть объект Type, представляющий тип B<int, V> из предыдущего примера. Метод GetGenericArguments предоставляет список аргументов типа, а при изучении класса V можно воспользоваться свойствами DeclaringMethod и DeclaringType, чтобы выявить источник этого класса. Затем при помощи свойства GenericParameterPosition можно определить его положение в списке параметров типа, где он был определен. В этом примере класс V находится в положении 0 (ноль) в списке параметров типа, где он был определен.

Ограничения для базового типа и интерфейса

Метод GetGenericParameterConstraints следует использовать для получения ограничения базового типа и ограничений интерфейса для параметра типа. Порядок элементов массива не имеет значения. Элемент представляет ограничение интерфейса, если оно является типом интерфейса.

Атрибуты универсальных параметров

Свойство GenericParameterAttributes возвращает значение GenericParameterAttributes, показывающее вариацию (ковариацию или контрвариацию) и особые ограничения параметра типа.

Ковариация и контрвариация

Чтобы определить, является ли параметр типа ковариантным или контравариантным, примените маску GenericParameterAttributes.VarianceMask к значению GenericParameterAttributes, возвращаемому свойством GenericParameterAttributes. Если в результате будет получено поле GenericParameterAttributes.None, параметр типа является инвариантным. См. раздел Ковариация и контравариация в универсальных шаблонах.

Особые ограничения

Чтобы определить особые ограничения для параметра типа, примените маску GenericParameterAttributes.SpecialConstraintMask к значению GenericParameterAttributes, возвращаемому свойством GenericParameterAttributes. Если в результате будет получено поле GenericParameterAttributes.None, особые ограничения отсутствуют. Ограничение может определять, что тип, задаваемый параметром типа, должен быть ссылочным типом, быть типом, не поддерживающим значение null, и обладать конструктором по умолчанию.

К началу

Инварианты

Таблицу неизменяемых условий для общих терминов в отражении для универсальных типов см. в Type.IsGenericType. Дополнительные термины, относящиеся к универсальным методам, см. в MethodInfo.IsGenericMethod.

К началу

Связанные разделы

Заголовок

Описание

Практическое руководство. Изучение универсальных типов и создание их экземпляров при помощи отражения

Демонстрация использования свойств и методов Type и MethodInfo для просмотра универсальных типов.

Универсальные шаблоны в платформе .NET Framework

Описание универсальных шаблонов и их поддержки в .NET Framework.

Практическое руководство. Определение универсального типа с порождаемым отражением

Демонстрация использования порождения отражения создания универсальных типов в динамических сборках.

Просмотр сведений о типах

Описание класса Type и предоставление примеров программного кода, иллюстрирующих использование класса Type совместно с несколькими классами отражения для получения сведений о конструкторах, методах, полях, свойствах и событиях.

К началу