C# 4.0 полное руководство - 2011
Шрифт:
// Вывести возвращаемый тип и имя.
Console.Write(" " + t.Name + "(");
// Вывести параметры.
Parameterlnfo[] 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 ;
// Найти
for(x=0; х < ci.Length; х++) {
Parametgrlnfo[] pi = ci[x].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("ХпВызов методов для объекта reflectOb."); Console.WriteLine ;
Methodlnfo[] mi = t.GetMethods;
// Вызвать каждый метод, foreach(Methodlnfo m in mi) {
// Получить параметры.
Parameterlnfo[] 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[l] = 18;
m. Invoke(reflectOb, args);
}
else if(m.Name.CompareTo("Set")==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. Сначала получается перечень открытых конструкторов в следующей строке кода.
Constructorlnfo[] ci = t.GetConstructors ;
Затем
for(x=0; х < ci.Length; х++) {
Parameterlnfo[] 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);
После вызова метода Invoke переменная экземпляра reflectOb будет ссылаться на объект типа MyClass. А далее в программе выполняются соответствующие методы для экземпляра этого объекта.
Следует, однако, иметь в виду, что ради простоты в данном примере предполагается наличие лишь одного конструктора с двумя аргументами типа int. Очевидно, что в реальном коде придется дополнительно проверять соответствие типов каждого параметра и аргумента.
Получение типов данных из сборок
В предыдущем примере все сведения о классе MyClass были получены с помощью рефлексии, за исключением одного элемента: типа самого класса MyClass. Несмотря на то что сведения о классе получались в предыдущем примере динамически, этот пример опирался на тот факт, что имя типа MyClass было известно заранее и использовалось в операторе typeof для получения объекта класса Туре, по отношению к которому осуществлялось косвенное или непосредственное обращение к методам рефлексии. В некоторых случаях такой подход может оказаться вполне пригодным, но истинные преимущества рефлексии проявляются лишь тогда, когда доступные в программе типы данных определяются динамически в результате анализа содержимого других сборок.
Как следует из главы 16, сборка несет в себе сведения о типах классов, структур и прочих элементов данных, которые в ней содержатся. Прикладной интерфейс Reflection API позволяет загрузить сборку, извлечь сведения о ней и получить экземпляры объектов любых открыто доступных в ней типов. Используя этот механизм, программа может выявлять свою среду и использовать те функциональные возможности, которые могут оказаться доступными без явного их определения во время компиляции. Это очень эффективный и привлекательный принцип. Представьте себе, например, программу, которая выполняет роль "браузера типов", отображая типы данных, доступные в системе, или же инструментальное средство разработки, позволяющее визуально составлять программы из различных типов данных, поддерживаемых в системе. А поскольку все сведения о типах могут быть извлечены и проверены, то ограничений на применение рефлексии практически не существует.