Рефлексия методов
33C# --- Сборки .NET --- Рефлексия методов
С помощью методов и свойств класса Type можно получить подробные сведения о типе данных во время выполнения программы. Это довольно эффективное средство. Ведь получив сведения о типе данных, можно сразу же вызвать его конструкторы и методы или воспользоваться его свойствами. Следовательно, рефлексия позволяет использовать код, который не был доступен во время компиляции.
Прикладной интерфейс Reflection API весьма обширен и имеет ясную логическую структуру, поэтому, уяснив одну его часть, нетрудно понять и все остальное.
Чтобы проиллюстрировать базовый процесс рефлексии (и оценить пользу от System.Type), создадим новое консольное приложение. Это приложение будет отображать детали методов, свойств, полей и поддерживаемых интерфейсов (а также другие интересные элементы данных) для любого из типов, содержащихся как в самом приложении, так и в сборке mscorlib.dll (доступ к которой все приложения .NET получают автоматически). После создания соответствующего проекта первым делом необходимо импортировать пространство имен System.Reflection:
// Для выполнения рефлексии должно импортироваться это пространство имен
using System.Reflection;
Далее потребуется модифицировать класс Program, определив в нем ряд статических методов так, чтобы каждый из них принимал единственный параметр System.Type и возвращал void.
Имея в своем распоряжении объект класса Type, можно получить список методов, поддерживаемых отдельным типом данных, используя метод GetMethods(). Ниже приведена одна из форм, подходящих для этой цели:
Methodlnfo[] GetMethods()
Этот метод возвращает массив объектов класса MethodInfo, которые описывают методы, поддерживаемые вызывающим типом. Класс MethodInfo находится в пространстве имен System.Reflection.
Класс MethodInfo является производным от абстрактного класса MethodBase, который в свою очередь наследует от класса MemberInfo. Это дает возможность пользоваться всеми свойствами и методами, определенными в этих трех классах. Например, для получения имени метода служит свойство Name. Особый интерес вызывают два члена класса MethodInfo: ReturnType и GetParameters().
Возвращаемый тип метода находится в доступном только для чтения свойстве ReturnType, которое является объектом класса Type. Метод GetParameters() возвращает список параметров, связанных с анализируемым методом. Ниже приведена его общая форма:
ParameterInfo[] GetParameters();
Сведения о параметрах содержатся в объекте класса ParameterInfо. В классе ParameterInfо определено немало свойств и методов, описывающих параметры. Особое значение имеют два свойства: Name — представляет собой строку, содержащую имя параметра, a ParameterType — описывает тип параметра, который инкапсулирован в объекте класса Type.
Давайте рассмотрим пример:
using System;
using System.Reflection;
namespace Reflect
{
// Тестовый класс, содержащий некоторые конструкции
class MyTestClass
{
double d, f;
public MyTestClass(double d, double f)
{
this.d = d;
this.f = f;
}
public double Sum()
{
return d + f;
}
public void Info()
{
Console.WriteLine(@"d = {0}
f = {1}",d,f);
}
public void Set(int a, int b)
{
d = (double)a;
f = (double)b;
}
public void Set(double a, double b)
{
d = a;
f = b;
}
public override string ToString()
{
return "MyTestClass";
}
}
// В данном классе определены методы использующие рефлексию
class Reflect
{
// Данный метод выводит информацию о содержащихся в классе методах
public static void MethodReflectInfo<T> (T obj) where T: class
{
Type t = typeof(T);
// Получаем коллекцию методов
MethodInfo[] MArr = t.GetMethods();
Console.WriteLine("*** Список методов класса {0} ***\n",obj.ToString());
// Вывести методы
foreach (MethodInfo m in MArr)
{
Console.Write(" --> "+m.ReturnType.Name + " \t" + m.Name + "(");
// Вывести параметры методов
ParameterInfo[] p = m.GetParameters();
for (int i = 0; i < p.Length; i++)
{
Console.Write(p[i].ParameterType.Name + " " + p[i].Name);
if (i + 1 < p.Length) Console.Write(", ");
}
Console.Write(")\n");
}
}
}
class Program
{
static void Main()
{
MyTestClass mtc = new MyTestClass(12.0,3.5);
Reflect.MethodReflectInfo<MyTestClass>(mtc);
Console.ReadLine();
}
}
}
Вторая форма метода GetMethods()
Существует вторая форма метода GetMethods(), позволяющая указывать различные флажки для отфильтровывания извлекаемых сведений о методах. Ниже приведена эта общая форма метода GetMethods():
Methodlnfo[] GetMethods(BindingFlags флажки)
В этом варианте создаются только те методы, которые соответствуют указанным критериям. BindingFlags представляет собой перечисление. Ниже перечислен ряд наиболее часто используемых его значений:
- DeclaredOnly
Извлекаются только те методы, которые определены в заданном классе. Унаследованные методы в извлекаемые сведения не включаются
- Instance
Извлекаются методы экземпляра
- Nonpublic
Извлекаются методы, не являющиеся открытыми
- Public
Извлекаются открытые методы
- Static
Извлекаются статические методы
Два или несколько флажков можно объединить с помощью логической операции ИЛИ. Но как минимум флажок Instance или Static следует указывать вместе с флажком Public или NonPublic. В противном случае не будут извлечены сведения ни об одном из методов.
Форма BindingFlags метода GetMethods() чаще всего применяется для получения списка методов, определенных в классе, без дополнительного извлечения наследуемых методов. Это особенно удобно в тех случаях, когда требуется исключить получение сведений о методах, определяемых в классе конкретного объекта. В качестве примера попробуем выполнить следующую замену в вызове метода GetMethods() из предыдущей программы:
MethodInfo[] MArr = t.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.Instance | BindingFlags.Public);
Как видите, теперь выводятся только те методы, которые явно определены в классе MyTestClass.