Метод Туре.GetType() перегружен, чтобы можно было указать два параметра типа Boolean, один из которых контролирует необходимость генерирования исключения, когда тип не найден, а другой – необходимость игнорирования регистра символов в строке. В качестве примера рассмотрите следующий фрагмент программного кода.
// Получение информации типа с помощью метода Type.GetType()
// (не генерировать исключение, если SportsCar не найден,
// и игнорировать регистр символов).
Type t = Type.GetType(''CarLibrary.SportsCar", false, true);
В этом примере обратите внимание на то, что в строке, которую вы передаете в GetType(), ничего не говорится о компоновочном блоке, содержащем данный тип. В этом случае предполагается, что соответствующий тип определен в рамках компоновочного блока, выполняемого в настоящий момент. Если же вы хотите получить метаданные для типа из внешнего приватного компоновочного блока, то строковый параметр должен иметь формат абсолютного имени типа, за которым через запятую должно следовать понятное имя компоновочного блока, содержащего этот тип.
// Получение информации типа из внешнего компоновочного блока.
Type t = null;
t = Type.GetType("CarLibrary.SportsCar, CarLibrary");
Следует также знать о том, что в строке, передаваемой методу GetType(), может присутствовать знак "плюс" (+), используемый для обозначения вложенного типа. Предположим, что мы хотим получить информацию для перечня (SpyOptions), вложенного в класс JamesBondCar. Для этого мы должны написать следующее.
// Получение информации типа для вложенного перечня
// в рамках имеющегося компоновочного блока.
Type t = Type.GetType(''CarLibrary. JamesBondCar+SpyOptions");
Получение Туре с помощью typeof()
Наконец, можно получить информацию типа с помощью операции C# typeof.
// Получение Туре с помощью typeof.
Type t = typeof(SportsCar);
Подобно методу Type.GetType(), операция typeof оказывается полезной тем, что при ее использовании нет необходимости сначала создавать экземпляр объекта, чтобы затем извлечь из него информацию типа. Но при этом ваш базовый код все равно должен иметь информацию о типе во время компиляции.
Создание пользовательского приложения для просмотра метаданных
Чтобы очертить общие контуры процесса отображения (а также привести пример использования System.Type), мы создадим консольное приложение, которое назовем MyTypeViewer. Эта программа будет отображать подробную информацию о методах, свойствах, полях и поддерживаемых интерфейсах (и другую информацию) для любого типа из MyTypeViewer, а также из mscorlib.dll (напомним, что все приложения .NET автоматически получают доступ к этой базовой библиотеке классов).
Отображение методов
Мы модифицируем класс Program, чтобы определить ряд статических методов, каждый из которых будет иметь один параметр System.Type и возвращать void. Начнем с метода ListMethods(), который (как вы можете догадаться сами) печатает имена всех методов, определенных указанным на входе типом. При этом заметим, что Type.GetMethods() возвращает массив типов System.Reflection.MethodInfo.
// Отображение имен методов типа.
public static void ListMethods(Type t) {
Console.WriteLine("***** Методы *****");
MethodInfo[] mi = t.GetMethods();
foreach (MethodInfo m in mi) Console.WriteLine("-›{0}", m.Name);
Console.WriteLine(");
}
Здесь с помощью свойства MethodInfo.Name просто печатается имя метода. Как и следует предполагать, MethodInfo имеет много других членов, которые позволяют выяснить, является ли метод статическим, виртуальным или абстрактным. Кроме того, тип MethodInfo позволяет получить возвращаемое значение метода и множество его параметров. Реализацию ListMethods() мы с вами проанализируем чуть позже.
Отображение полей и свойств
Реализация ListFields() будет аналогичной. Единственным отличием будет вызов Type.GetFields(), а результирующим массивом будет FieldInfo. Для простоты мы печатаем только имена полей.
// Отображение имен полей типа.
public static void ListFields(Type t) {
Console.WriteLine("***** Поля *****");
FieldInfo[] fi = t.GetFields();
foreach (FieldInfo field in fi) Console.WriteLine("-›{0}", field.Name);
Console.WriteLine(");
}
Логика отображения свойств типа аналогична.
// Отображение имен свойств типа.
public static void ListProps(Type t) {
Console.WriteLine("***** Свойства *****");
PropertyInfo[] pi = t.GetProperties();
foreach(PropertyInfo prop in pi) Console.WriteLine("-›{0}", prop.Name);
Console.WriteLine(");
}
Отображение реализованных интерфейсов
Теперь построим метод ListInterfaces(), который будет печатать имена интерфейсов, поддерживаемых указанным на входе типом. Единственным заслуживающим внимания моментом здесь является вызов GetInterfaces(), возвращающий массив System.Types. Это логично, поскольку интерфейсы тоже являются типами.
// Отображение реализованных интерфейсов.
public static void ListInterfaces(Type t) {
Console.WriteLine("***** Интерфейсы *****");
Type[] ifaсes = t.GetInterfaces();
foreach (Type i in ifaces) Console.WriteLine("-› {0}", i.Name);
}
Отображение вспомогательной информации
Наконец, мы рассмотрим еще один вспомогательный метод. который будет отображать различные статистические характеристики типа (является ли тип обобщенным, какой тип для него является базовым, изолирован ли он и т.д.).
// Отображаются для полноты картины.
public static void ListVariousStats(Type t) {
Console.WriteLine("***** Вcпомогательная информация *****");
Console.WriteLine("Базовый класс: {0}", t.BaseType);
Console.WriteLine("Это абстрактный тип? {0}", t.IsAbstract);
Console.WriteLine("Это изолированный тип? {'0}", t.IsSealed);
Console.WriteLine("Это обобщенный тип? {0}", t.IsGenericTypeDefinition);
Console.WriteLine("Это тип класса? {0}", t.IsClass);
Console.WriteLine(");
}
Реализация Main()
Метод Main() класса Program запрашивает у пользователя абсолютное имя типа. После получения строковых данных они передаются методу Туре.GetType(), а извлеченный объект System.Type отправляется каждому из вспомогательных методов. Это повторяется до тех пор, пока пользователь не нажмет клавишу ‹Q›, чтобы завершить выполнение приложения.
// Здесь необходимо указать пространство имен отображения.
using System;
using System.Reflection;
...
static void Main(string[] args) {
Console.WriteLine("***** Добро пожаловать в MyTypeViewer! *****");
string typeName = ";
bool userIsDone = false;
do {
Console.WriteLine("nВведите имя типа");
Console.Write("или нажмите Q для выхода из приложения: ");
// Получение имени типа.
typeName = Console.ReadLine();
// Желает ли пользователь завершить работу приложения?
if (typeName.ToUpper() = "Q") {
userIsDone = true;
break;
}
// Попытка отображения типа.
try {
Type t = Type.GetType(typeName);
Console.WriteLine("");
ListVariousStats(t);
ListFields(t);
ListProps(t);
ListMethods(t);
ListInterfaces(t);
} catch {
Console.WriteLine("Извините, указанный тип не найден");
}
} while (userIsDone);
}
К этому моменту приложение MyTypeViewer.exe уже готово для тестового запуска. Запустите это приложение и введите следующие абсолютные имена (помните о том, что при используемом здесь варианте вызова Туре.GetType() строки имен оказываются чувствительными к регистру символов).
• System.Int32
• System.Collections.ArrayList
• System.Threading.Thread
• System.Void
• System.IO.BinaryWriter
• System.Math
• System.Console
• MyTypeViewer.Program
На рис. 12.2 показана информация для случая, соответствующего выбору типа System.Math.
Риc. 12.2. Отображение System.Math
Отображение параметров и возвращаемых значений методов
Итак, всё работает. Теперь немного усовершенствуем наше приложение. В частности, модифицируем вспомогательную функцию ListMethods(), чтобы получать не только имя метода, но и возвращаемое значение, а также входные параметры. Для решения именно таких задач тип MethodInfo предлагает свойство ReturnType и метод GetParameters().
В следующем фрагменте программного кода обратите внимание на то, что строка, содержащая тип и имя каждого из параметров, строится с помощью вложенного цикла foreach.