Класс System.Туре составляет ядро подсистемы рефлексии, поскольку он ин капсулирует тип данных. Он содержит многие свойства и методы, которыми можно пользоваться для получения информации о типе данных во время выполнения. Класс Туре является производным от абстрактного класса System.Reflection. MemberInfo.
В классе MemberInfo определены приведенные ниже свойства, доступные только для чтения. Свойство Описание Type DeclaringType Тип класса или интерфейса, в котором объявляется отражаемый член MemberTypes MemberTypesТип члена. Это значение обозначает, является ли член полем, методом, свойством, событием или конструктором int MetadataToken Значение, связанное к конкретными метаданными Module Module Объект типа Module, представляющий модуль (исполняемый файл), в котором находится отражаемый тип string Name Имя типа Type ReflectedType Тип отражаемого объекта
Следует иметь в виду, что свойство MemberType возвращает тип MemberTypes — перечисление, в котором определяются значения, обозначающие различные типы чле нов. К их числу относятся следующие. MemberTypes.Constructor MemberTypes.Method MemberTypes.Field MemberTypes.Event MemberTypes.Property
Следовательно, тип члена можно определить, проверив свойство MemberType. Так, если свойство MemberType имеет значение MemberTypes.Method, то проверяемый член является методом.
В класс MemberInfo входят два абстрактных метода: GetCustomAttributes() и IsDefined(). Оба метода связаны с атрибутами. Первый из них получает список специальных атрибутов, имеющих отношение к вызывающему объекту, а второй уста навливает, определен ли атрибут для вызывающего метода. В версию .NET Framework Version 4.0 внедрен метод GetCustomAttributesData(), возвращающий сведения о специальных атрибутах. (Подробнее об атрибутах речь пойдет далее в этой главе.)
Класс Туре добавляет немало своих собственных методов и свойств к числу тех, что определены в классе MemberInfo. В качестве примера ниже перечислен ряд наиболее часто используемых методов класса Туре. Метод Назначение ConstructorInfo[] GetConstructors() Получает список конструкторов для заданного типа EventInfo[] GetEvents() Получает список событий для заданного типа FieldInfo[] GetFields() Получает список полей для заданного типа Type[] GetGenericArguments() Получает список аргументов типа, связанных с закрыто сконструированным обобщенным типом, или же список параметров типа, если заданный тип определен как обобщенный. Для открыто сконструированного типа этот список может содержать как аргументы, так и параметры типа. (Более подробно обобщения рассматриваются в главе 18.) MemberInfо[] GetMembers() Получает список членов для заданного типа MethodInfo[] GetMethods() Получает список методов для заданного типа PropertyInfo[] GetProperties() Получает список свойств для заданного типа
Далее приведен ряд наиболее часто используемых свойств, доступных только для чтения и определенных в классе Туре. Свойство Назначение Assembly Assembly Получает сборку для заданного типа TypeAttributes Attributes Получает атрибуты для заданного типа Type BaseType Получает непосредственный базовый тип для заданного типа string FullName Получает полное имя заданного типа bool IsAbstract Истинно, если заданный тип является абстрактным bool IsArray Истинно, если заданный тип является массивом bool IsClass Истинно, если заданный тип является классом bool IsEnum Истинно, если заданный тип является перечислением bool IsGenericParameter Истинно, если заданный тип является параметром обобщенного типа. (Более подробно обобщения рассматриваются в главе 18.) bool IsGenericType Истинно, если заданный тип является обобщенным. (Более подробно обобщения рассматриваются в главе 18.) string Namespace Получает пространство имен для заданного типа Применение рефлексии
С помощью методов и свойств класса Туре можно получить подробные сведения о типе данных во время выполнения программы. Это довольно эффективное средство. Ведь получив сведения о типе данных, можно сразу же вызвать его конструкторы и методы или воспользоваться его свойствами. Следовательно, рефлексия позволяет ис пользовать код, который не был доступен во время компиляции.
Прикладной интерфейс Reflection API весьма обширен и поэтому не может быть полностью рассмотрен в этой главе. Ведь для этого потребовалась бы целая книга! Но прикладной интерфейс Reflection API имеет ясную логическую структуру, а следова тельно, уяснив одну его часть, нетрудно понять и все остальное. Принимая во внима ние это обстоятельство, в последующих разделах демонстрируются четыре основных способа применения рефлексии: получение сведений о методах, вызов методов, кон струирование объектов и загрузка типов данных из сборок. Получение сведений о методах
Имея в своем распоряжении объект класса Туре, можно получить список методов, поддерживаемых отдельным типом данных, используя метод GetMethods(). Ниже приведена одна из форм, подходящих для этой цели. MethodInfo[] GetMethods()
Этот метод возвращает массив объектов класса MethodInfo, которые описывают методы, поддерживаемые вызывающим типом. Класс MethodInfo находится в про странстве имен System.Reflection.
Класс MethodInfo является производным от абстрактного класса MethodBase, ко торый в свою очередь наследует от класса MemberInfо. Это дает возможность пользо ваться всеми свойствами и методами, определенными в этих трех классах. Например, для получения имени метода служит свойство Name. Особый интерес вызывают два члена класса MethodInfo:ReturnType и GetParameters().
Возвращаемый тип метода находится в доступном только для чтения свойстве ReturnType, которое является объектом класса Туре.
Метод GetParameters() возвращает список параметров, связанных с анализируе мым методом. Ниже приведена его общая форма. ParameterInfо[] GetParameters();
Сведения о параметрах содержатся в объекте класса ParameterInfо. В классе ParameterInfо определено немало свойств и методов, описывающих параметры. Особое значение имеют два свойства: Name — представляет собой строку, содержащую имя параметра, a ParameterType — описывает тип параметра, который инкапсули рован в объекте класса Туре.
В качестве примера ниже приведена программа, в которой рефлексия используется для получения методов, поддерживаемых классом MyClass. В этой программе выво дится возвращаемый тип и имя каждого метода, а также имена и типы любых параме тров, которые может иметь каждый метод. // Анализ методов с помощью рефлексии. using System; using System.Reflection; class MyClass { int x; int y; public MyClass(int i, int j) { x = i; у = j; } public int Sum() { return x+y; } public bool IsBetween(int i) { if(x < i && i < y) return true; else return false; } public void Set(int a, int b) { x = a; у = b; } public void Set(double a, double b) { x = (int) a; y = (int) b; } public void Show() { Console.WriteLine(" x: {0}, у: {1}", x, y); } } class ReflectDemo { static void Main() { Type t = typeof(MyClass); // получить объект класса Type, // представляющий класс MyClass Console.WriteLine("Анализ методов, определенных " + "в классе " + t.Name); Console.WriteLine(); Console.WriteLine("Поддерживаемые методы: "); MethodInfo[] mi = t.GetMethods(); // Вывести методы, поддерживаемые в классе MyClass. foreach(MethodInfo m in mi) { // Вывести возвращаемый тип и имя каждого метода. Console.Write(" " + m.ReturnType.Name + " " + m.Name + "("); // Вывести параметры. ParameterInfo[] pi = m.GetParameters(); for(int i=0; i < pi.Length; i++) { Console.Write(pi[i].ParameterType.Name + " " + pi[i],Name); if(i+1 < pi.Length) Console.Write(", "); } Console.WriteLine(")"); Console.WriteLine(); } } }
Эта программа дает следующий результат. Анализ методов, определенных в классе MyClass Поддерживаемые методы: Int32 Sum() Boolean IsBetween(Int32 i) Void Set(Int32 a, Int32 b) Void Set(Double a, Double b) Void Show() String ToString() Boolean Equals(Object obj) Int32 GetHashCode() Type GetType()
Как видите, помимо методов, определенных в классе MyClass, в данной программе выводятся также методы, определенные в классе object, поскольку все типы данных в C# наследуют от класса object. Кроме того, в качестве имен типов указываются имена структуры .NET. Обратите также внимание на то, что метод Set() выводится дважды, поскольку он перегружается. Один из его вариантов принимает аргументы типа int, а другой — аргументы типа double.
Рассмотрим эту программу более подробно. Прежде всего следует заметить, что в классе MyClass определен открытый конструктор и ряд открытых методов, в том числе и перегружаемый метод Set().
Объект класса Туре, представляющий класс MyClass, создается в методе Main() в следующей строке кода. Type t = typeof(MyClass); // получить объект класса Туре, // представляющий класс MyClass
Напомним, что оператор typeof возвращает объект класса Туре, представляющий конкретный тип данных (в данном случае — класс MyClass).
С помощью переменной t и прикладного интерфейса Reflection API в данной программе затем выводятся сведения о методах, поддерживаемых в классе MyClass. Для этого в приведенной ниже строке кода сначала выводится список соответствую щих методов. MethodInfo[] mi = t.GetMethods();
Затем в цикле foreach организуется обращение к элементам массива mi. На каж дом шаге этого цикла выводится возвращаемый тип, имя и параметры отдельного ме тода, как показано в приведенном ниже фрагменте кода. foreach(MethodInfo m in mi) { // Вывести возвращаемый тип и имя каждого метода. Console.Write(" " + m.ReturnType.Name + " " + m.Name + "("); // Вывести параметры. ParameterInfo[] pi = m.GetParameters(); for(int i=0; i < pi.Length; i++) { Console.Write(pi[i].ParameterType.Name + " " + pi[i].Name); if(i+1 < pi.Length) Console.Write(", "); } }
В этом фрагменте кода параметры, связанные с каждым методом, сначала создают ся с помощью метода GetParameters() и сохраняются в массиве pi. Затем в цикле for происходит обращение к элементам массива pi и выводится тип и имя каждо го параметра. Самое главное, что все эти сведения создаются динамически во время выполнения программы, не опираясь на предварительную осведомленность о классе MyClass. Вторая форма метода GetMethods()