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

на главную - закладки

Жанры

Полное руководство. С# 4.0
Шрифт:

После этой замены программа дает следующий результат. Анализ методов, определенных в классе MyClass Поддерживаемые методы: Int32 Sum Boolean IsBetween(Int32 i) Void Set(Int32 a, Int32 b) Void Set(Double a, Double b) Void Show

Как видите, теперь выводятся только те методы, которые явно определены в классе MyClass. Вызов методов с помощью рефлексии

Как только методы, поддерживаемые определенным типом данных, становятся из вестны, их можно вызывать. Для этой цели служит метод Invoke, входящий в со став класса MethodInfo. Ниже приведена одна из форм этого метода: object Invoke(object obj, object[] parameters)

где obj обозначает ссылку на объект, для которого вызывается метод. Для вызова стати ческих методов (static) в качестве параметра obj передается пустое значение (null). Любые аргументы, которые должны быть переданы методу, указываются в массиве parameters. Если же аргументы не нужны, то вместо массива parameters указыва ется пустое

значение (null). Кроме того, количество элементов массива parameters должно точно соответствовать количеству передаваемых аргументов. Так, если требует ся передать два аргумента, то массив parameters должен состоять из двух элементов, но не из трех или четырех. Значение, возвращаемое вызываемым методом, передается методу Invoke, который и возвращает его.

Для вызова конкретного метода достаточно вызвать метод Invoke для экзем пляра объекта типа MethodInfo, получаемого при вызове метода GetMethods. Эта процедура демонстрируется в приведенном ниже примере программы. // Вызвать методы с помощью рефлексии. 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) { Console.Write("В методе Set(int, int). "); x = a; У = b; Show; } // Перегрузить метод Set. public void Set(double a, double b) { Console.Write("В методе Set(double, double). "); x = (int) a; у = (int) b; Show; } public void Show { Console.WriteLine("Значение x: {0}, значение у: {1}", x, у); } } class InvokeMethDemo { static void Main { Type t = typeof(MyClass); MyClass reflectOb = new MyClass(10, 20); int val; Console.WriteLine("Вызов методов, определенных в классе " + t.Name); Console.WriteLine; MethodInfo[] mi = t.GetMethods; // Вызвать каждый метод. foreach(MethodInfo m in mi) { // Получить параметры. ParameterInfo[] pi = m.GetParameters; if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(int)) { object[] args = new object[2]; args[0] = 9; args[1] = 18; m.Invoke(reflectOb, args); } else if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(double)) { object[] args = new object[2]; args[0] = 1.12; args[1] = 23.4; m.Invoke(reflectOb, args); } else if(m.Name.CompareTo("Sum")==0) { val = (int) m.Invoke(reflectOb, null); Console.WriteLine("Сумма равна " + val); } else if(m.Name.CompareTo("IsBetween")==0) { object[] args = new object[1]; args[0] = 14; if((bool) m.Invoke(reflectOb, args)) Console.WriteLine("Значение 14 находится между x и у"); } else if(m.Name.CompareTo("Show")==0) { m.Invoke(reflectOb, null); } } } }

Вот к какому результату приводит выполнение этой программы. Вызов методов, определенных в классе MyClass Сумма равна 30 Значение 14 находится между х и у В методе Set(int, int). Значение х: 9, значение у: 18 В методе Set(double, double). Значение х: 1, значение у: 23 Значение х: 1, значение у: 23

Рассмотрим подробнее порядок вызова методов. Сначала создается список методов. Затем в цикле foreach извлекаются сведения об их параметрах. Далее каждый метод вызывается с указанием соответствующего типа и числа аргументов в последователь ном ряде условных операторов if/else. Обратите особое внимание на перегрузку ме тода Set в приведенном ниже фрагменте кода. if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(int)) { object[] args = new object[2]; args[0] = 9; args[1] = 18; m.Invoke(reflectOb, args); } else if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(double)) { object[] args = new object[2]; args[0] = 1.12; args[1] = 23.4; m.Invoke(reflectOb, args); }

Если имя метода — Set, то проверяется тип первого параметра, чтобы выявить конкретный вариант этого метода. Так, если это метод Set(int, int), то его аргу менты загружаются в массив args. В противном случае используются аргументы типа double. Получение конструкторов конкретного типа

В предыдущем примере при вызове методов, определенных в классе MyClass, пре имущества рефлексии не использовались, поскольку объект типа MyClass создавал ся явным образом. В таком случае было бы намного проще вызвать для него методы обычным образом. Но сильные стороны рефлексии проявляются наиболее заметно лишь в том случае, если объект создается динамически во время выполнения. И для этого необходимо получить сначала список конструкторов, а затем экземпляр объекта заданного типа, вызвав один из этих конструкторов. Такой механизм позволяет полу чать во время выполнения экземпляр объекта любого типа, даже не указывая его имя в операторе объявления.

Конструкторы конкретного типа получаются при вызове метода GetConstructors для объекта класса Туре. Ниже приведена одна из наиболее ча сто используемых форм этого метода. ConstructorInfо[] GetConstructors

Метод GetConstructors возвращает массив объектов класса ConstructorInfо, описывающих конструкторы.

Класс ConstructorInfo является производным от абстрактного класса MethodBase,

который в свою очередь наследует от класса MemberInfо. В нем также определен ряд собственных методов. К их числу относится интересующий нас метод GetConstructors, возвращающий список параметров, связанных с конструк тором. Этот метод действует таким же образом, как и упоминавшийся ранее метод GetParameters, определенный в классе MethodInfo.

Как только будет обнаружен подходящий конструктор, для создания объекта вызы вается метод Invoke, определенный в классе ConstructorInfo. Ниже приведена одна из форм этого метода. object Invoke(object[] parameters)

Любые аргументы, которые требуется передать методу, указываются в масси ве parameters. Если же аргументы не нужны, то вместо массива parameters ука зывается пустое значение (null). Но в любом случае количество элементов массива parameters должно совпадать с количеством передаваемых аргументов, а типы аргу ментов — с типами параметров. Метод Invoke возвращает ссылку на сконструиро ванный объект.

В приведенном ниже примере программы рефлексия используется для создания экземпляра объекта класса MyClass. // Создать объект с помощью рефлексии. using System; using System.Reflection; class MyClass { int x; int y; public MyClass(int i) { Console.WriteLine("Конструирование класса MyClass(int, int). "); x = у = i; } public MyClass(int i, int j) { Console.WriteLine("Конструирование класса MyClass(int, int). "); x = i; У = j; Show; } 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) { Console.Write("В методе Set(int, int). "); x = a; У = b; Show; } // Перегрузить метод Set. public void Set(double a, double b) { Console.Write("В методе(double, double). "); x = (int) a; у = (int) b; Show; } public void Show { Console.WriteLine("Значение x: {0}, значение у: {1}", x, у); } } class InvokeConsDemo { static void Main { Type t = typeof(MyClass); int val; // Получить сведения о конструкторе. ConstructorInfо[] ci = t.GetConstructors; Console.WriteLine("Доступные конструкторы: "); foreach(ConstructorInfo с in ci) { // Вывести возвращаемый тип и имя. Console.Write(" " + t.Name + "("); // Вывести параметры. ParameterInfо[] pi = с.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; // Найти подходящий конструктор. int х; for(x=0; х < ci.Length; х++) { ParameterInfо[] pi = ci[х].GetParameters; if(pi.Length == 2) break; } if(x == ci.Length) { Console.WriteLine("Подходящий конструктор не найден."); return; } else Console.WriteLine("Найден конструктор с двумя параметрами.\n"); // Сконструировать объект. object[] consargs = new object[2]; consargs[0] = 10; consargs[1] = 20; object reflectOb = ci[x].Invoke(consargs); Console.WriteLine("\nВызов методов для объекта reflectOb."); Console.WriteLine; MethodInfo[] mi = t.GetMethods; // Вызвать каждый метод. foreach(MethodInfo m in mi) { // Получить параметры. ParameterInfо[] pi = m.GetParameters; if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(int)) { // Это метод Set(int, int). object[] args = new object[2]; args[0] = 9; args[1] = 18; m.Invoke(reflectOb, args); } else if(m.Name.CompareTo("Set")==0 && pi[0].ParameterType == typeof(double)) { // Это метод Set(double, double). object[] args = new object[2]; args[0] = 1.12; args[1] = 23.4; m.Invoke(reflectOb, args); } else if(m.Name.CompareTo("Sum")==0) { val = (int) m.Invoke(reflectOb, null); Console.WriteLine("Сумма равна " + val); } else if(m.Name.CompareTo("IsBetween")==0) { object[] args = new object[1]; args[0] = 14; if((bool) m.Invoke(reflectOb, args)) Console.WriteLine("Значение 14 находится между x и у"); } else if(m.Name.CompareTo("Show")==0) { m.Invoke(reflectOb, null); } } } }

Эта программа дает следующий результат. Доступные конструкторы: MyClass(Int32 i) MyClass(Int32 i, Int32 j) Найден конструктор с двумя параметрами. Конструирование класса MyClass(int, int) Значение х: 10, значение у: 20 Вызов методов для объекта reflectOb Сумма равна 30 Значение 14 находится между х и у В методе Set(int, int). Значение х: 9, значение у: 18 В методе Set(double, double). Значение х: 1, значение у: 23 Значение х: 1, значение у: 23

А теперь рассмотрим порядок применения рефлексии для конструирования объек та класса MyClass. Сначала получается перечень открытых конструкторов в следую щей строке кода. ConstructorInfо[] ci = t.GetConstructors;

Затем для наглядности примера выводятся полученные конструкторы. После этого осуществляется поиск по списку конструктора, принимающего два аргумента, как по казано в приведенном ниже фрагменте кода. for(x=0; х < ci.Length; х++) { ParameterInfo[] pi = ci[x].GetParameters; if(pi.Length == 2) break; }

Если такой конструктор найден, как в данном примере, то в следующем фрагменте кода получается экземпляр объекта заданного типа. // Сконструировать объект. object[] consargs = new object[2]; consargs[0] = 10; consargs[1] = 20; object reflectOb = ci[x].Invoke(consargs);

Поделиться:
Популярные книги

Жалкая

Макинтайер Эмили
3. Долго и Несчастливо
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Жалкая

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец

Академия проклятий. Книги 1 - 7

Звездная Елена
Академия Проклятий
Фантастика:
фэнтези
8.98
рейтинг книги
Академия проклятий. Книги 1 - 7

Измена. Верни мне мою жизнь

Томченко Анна
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Верни мне мою жизнь

Измена

Рей Полина
Любовные романы:
современные любовные романы
5.38
рейтинг книги
Измена

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Сердце для стража

Каменистый Артем
5. Девятый
Фантастика:
фэнтези
боевая фантастика
9.20
рейтинг книги
Сердце для стража

Черный Маг Императора 11

Герда Александр
11. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Черный Маг Императора 11

Имя нам Легион. Том 3

Дорничев Дмитрий
3. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 3

Жена фаворита королевы. Посмешище двора

Семина Дия
Фантастика:
фэнтези
5.00
рейтинг книги
Жена фаворита королевы. Посмешище двора

Как я строил магическую империю 5

Зубов Константин
5. Как я строил магическую империю
Фантастика:
попаданцы
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 5

Блуждающие огни 2

Панченко Андрей Алексеевич
2. Блуждающие огни
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Блуждающие огни 2

Ратник

Ланцов Михаил Алексеевич
3. Помещик
Фантастика:
альтернативная история
7.11
рейтинг книги
Ратник

Маленькая слабость Дракона Андреевича

Рам Янка
1. Танцы на углях
Любовные романы:
современные любовные романы
эро литература
5.25
рейтинг книги
Маленькая слабость Дракона Андреевича