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

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

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

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

    Примечание

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

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

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

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

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

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

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

Это определение универсального типа или метода?

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

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

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

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

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

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

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

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

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

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

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

Используйте метод Type.GetGenericArguments , чтобы получить массив объектов Type , которые представляют параметры типа или аргументы типа для универсального типа; используйте метод 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. Дополнительные термины, связанные с универсальными методами, см. в разделе MethodBase.IsGenericMethod.

Заголовок Описание
Практическое руководство. Изучение универсальных типов и создание их экземпляров при помощи отражения Показано использование свойств и методов Type и MethodInfo для изучения универсальных типов.
Универсальные шаблоны Описана универсальность и поддержка этой технологии в .NET Framework.
Практическое руководство. Определение универсального типа с порождаемым отражением Показано использование порождения отражения для создания универсальных типов в динамических сборках.
Просмотр сведений о типах Описывается класс Type и приводятся примеры кода, иллюстрирующие использование Type с несколькими классами отражения для получения информации о конструкторах, методах, полях, свойствах и событиях.