Шрифт:
Интервал:
Закладка:
Рассмотрим следующий пример, демонстрирующий полностью автоматизированное обнаружение типов. В этом примере сначала загружается сборка MyClasses.ехе, затем конструируется объект класса MyClass и далее вызываются все методы, объявленные в классе MyClass, причем о них ничего заранее неизвестно.
// Использовать класс MyClass, ничего не зная о нем заранее.
using System;
using System.Reflection;
class ReflectAssemblyDemo {
static void Main() {
int val;
Assembly asm = Assembly.LoadFrom("MyClasses.exe");
Type[] alltypes = asm.GetTypes();
Type t = alltypes[0]; // использовать первый обнаруженный класс
Console.WriteLine("Использовано: " + t.Name);
ConstructorInfo[] ci = t.GetConstructors();
// Использовать первый обнаруженный конструктор.
ParameterInfo[] cpi = ci[0].GetParameters();
object reflectOb;
if (cpi.Length > 0) {
object[] consargs = new object[cpi.Length];
// Инициализировать аргументы,
for (int n = 0; n < cpi.Length; n++) consargs[n] = 10 + n * 20;
// Сконструировать объект.
reflectOb = ci[0].Invoke(consargs);
}
else
reflectOb = ci[0].Invoke(null);
Console.WriteLine("nВызов методов для объекта reflectOb.");
Console.WriteLine();
// Игнорировать наследуемые методы.
MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.Instance | BindingFlags.Public);
// Вызвать каждый метод,
foreach (MethodInfo m in mi) {
Console.WriteLine("Вызов метода {0} ", m.Name);
// Получить параметры.
ParameterInfo[] pi = m.GetParameters();
// Выполнить методы,
switch (pi.Length) {
case 0: // аргументы отсутствуют
if (m.ReturnType == typeof(int)) {
val = (int)m.Invoke(reflectOb, null);
Console.WriteLine("Результат: " + val);
}
else if (m.ReturnType == typeof(void)) {
m.Invoke(reflectOb, null);
}
break;
case 1: // один аргумент
if (pi[0].ParameterType == typeof(int)) {
object[] args = new object[1];
args[0] = 14;
if ((bool)m.Invoke(reflectOb, args))
Console.WriteLine("Значение 14 находится между x и у");
else
Console.WriteLine("Значение 14 не находится между х и у");
}
break;
case 2: // два аргумента
if ((pi[0].ParameterType == typeof(int)) &&
(pi[1].ParameterType == typeof(int))) {
object[] args = new object[2];
args[0] = 9;
args[1] = 18;
m.Invoke(reflectOb, args);
}
else if ((pi[0].ParameterType == typeof(double)) &&
(pi[1].ParameterType == typeof(double))) {
object[] args = new object[2];
args[0] = 1.12;
args[1] = 23.4;
m.Invoke(reflectOb, args);
}
break;
}
Console.WriteLine();
}
}
}
Эта программа дает следующий результат.
Использовано: MyClass
Конструирование класса MyClass(int).
Значение х: 10, значение у: 10
Вызов методов для объекта reflectOb.
Вызов метода Sum
Результат: 20
Вызов метода IsBetween
Значение 14 не находится между х и у
Вызов метода Set
В методе Set (int, int). Значение х: 9, значение у: 18
Вызов метода Set
В методе Set(double, double). Значение х: 1, значение у: 23
Вызов метода Show
Значение х: 1, значение у: 23
Эта программа работает довольно просто, но все же требует некоторых пояснений. Во-первых, получаются и используются только те методы, которые явно объявлены в классе MyClass. Для этой цели служит форма BindingFlags метода GetMethods(), чтобы воспрепятствовать вызову методов, наследуемых от объекта. И во-вторых, количество параметров и возвращаемый тип каждого метода получаются динамически, а затем определяются и проверяются в операторе switch. На основании этой информации формируется вызов каждого метода.
Атрибуты
В C# разрешается вводить в программу информацию декларативного характера в форме атрибута, с помощью которого определяются дополнительные сведения (метаданные), связанные с классом, структурой, методом и т.д. Например, в программе можно указать атрибут, определяющий тип кнопки, которую должен отображать конкретный класс. Атрибуты указываются в квадратных скобках перед тем элементом, к которому они применяются. Следовательно, атрибут не является членом класса, но обозначает дополнительную информацию, присоединяемую к элементу.
Основы применения атрибутовАтрибут поддерживается классом, наследующим от класса System.Attribute. Поэтому классы атрибутов должны быть подклассами класса Attribute. В классе Attribute определены основные функциональные возможности, но далеко не все они нужны для работы с атрибутами. В именах классов атрибутов принято употреблять суффикс Attribute. Например, ErrorAttribute — это имя класса атрибута, описывающего ошибку.
При объявлении класса атрибута перед его именем указывается атрибут AttributeUsage. Этот встроенный атрибут обозначает типы элементов, к которым может применяться объявляемый атрибут. Так, применение атрибута может ограничиваться одними методами.
Создание атрибутаВ классе атрибута определяются члены, поддерживающие атрибут. Классы атрибутов зачастую оказываются довольно простыми и содержат небольшое количество полей или свойств. Например, атрибут может определять примечание, описывающее элемент, к которому присоединяется атрибут. Такой атрибут может принимать следующий вид.
[AttributeUsage(AttributeTargets.All) ]
public class RemarkAttribute : Attribute {
string pri_remark; // базовое поле свойства Remark
public RemarkAttribute(string comment) {
pri_remark = comment;
}
public string Remark {
get {
return pri_remark;
}
}
}
Проанализируем этот класс атрибута построчно.
Объявляемый атрибут получает имя RemarkAttribute. Его объявлению предшествует встроенный атрибут AttributeUsage, указывающий на то, что атрибут RemarkAttribute может применяться ко всем типам элементов. С помощью встроенного атрибута AttributeUsage можно сузить перечень элементов, к которым может присоединяться объявляемый атрибут. Подробнее о его возможностях речь пойдет далее в этой главе.
Далее объявляется класс RemarkAttribute, наследующий от класса Attribute. В классе RemarkAttribute определяется единственное закрытое поле pri_remark, поддерживающее одно открытое и доступное для чтения свойство Remark. Это свойство содержит описание, связываемое с атрибутом. (Конечно, Remark можно было бы объявить как автоматически реализуемое свойство с закрытым аксессором set, но ради наглядности данного примера выбрано свойство, доступное только для чтения.) В данном классе определен также один открытый конструктор, принимающий строковый аргумент и присваивающий его свойству Remark. Этим пока что ограничиваются функциональные возможности класса RemarkAttribute, готового к применению.
- QT 4: программирование GUI на С++ - Жасмин Бланшет - Программирование
- C# для профессионалов. Том II - Симон Робинсон - Программирование
- ИНФОРМАЦИОННАЯ ТЕХНОЛОГИЯ. РУКОВОДСТВО ПО УПРАВЛЕНИЮ ДОКУМЕНТИРОВАНИЕМ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ - ГОССТАНДАРТ РОССИИ - Программирование
- Управление исходными текстами. Часть 1. Краткое руководство по CVS - Илья Рыженков - Программирование
- Гибкое управление проектами и продуктами - Борис Вольфсон - Программирование
- Каждому проекту своя методология - Алистэр Коуберн - Программирование
- Разработка ядра Linux - Роберт Лав - Программирование
- Как спроектировать современный сайт - Чои Вин - Программирование
- Творческий отбор. Как создавались лучшие продукты Apple во времена Стива Джобса - Кен Косиенда - Прочая околокомпьтерная литература / Интернет / Программирование
- Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT. Часть 2 - Александр Фролов - Программирование