Иллюстрированный самоучитель по Architecture .NET

Динамическое связывание

Отражение может также использоваться для реализации динамического связывания. Динамическое связывание состоит в том, что метод, который нужно вызвать, определяется в процессе выполнения, а не на этапе компиляции. Это один из примеров того, как метаданные используются для предоставления функциональных возможностей. Предыдущий пример демонстрирует, как получить сигнатуру метода, связанного с типом. Объект Methodlnfо содержит все необходимые метаданные для метода класса. Пример Dynamic (Динамический) демонстрирует очень простой случай динамического связывания.

Мы динамически загружаем сборку и получаем метаданные для метода определенного типа:

// Загрузить (Load) сборку Customer (Клиент)
Assembly *a = Assembly::Load("Customer");
// Загрузка ("Клиент")
// Получить метаданных для класса Customers (Клиенты)
// и одного метода
Type *t = a › GetType("01. NetCpp.Acme.Customers"); // Клиенты
Methodlnfо *mi = t › GetMethod("GetCustomer");

Вот что следует помнить программистам при программировании на C++. Работая со строками, которые содержат пространства имен или классы, необходимо использовать должным образом отформатированные строки, которые понятны методам класса отражения. Например, полностью определенное имя класса в вышеописанном коде – OI. NetCpp.Acme.Customers, а не OI::NetCpp::Acme::Customers, отформатированное в стиле C++. Таким образом, используемый формат подобен формату в С#, а не в C++.

Применяя классы отражения, мы могли бы сделать все это полностью динамически, произвольно выбирая типы, методы, и конструкторы из сборки Customer (Клиент), используя методы последнего примера, но мы хотели сохранить пример Dynamic (Динамический) простым. Более честолюбивая программа могла бы делать что-нибудь гораздо более интересное, вроде реализации декомпилятора сборки, который непосредственно из откомпилированной сборки генерирует исходный текст на управляемом C++, С#илиУВ.НЕТ.

Пространство имен System (Система) содержит класс Activator (Активатор, Модуль активизации), в котором перегружается метод Createlnstance, предназначенный для создания экземпляров любого типа .NET с помощью подходящего конструктора. Класс Activator (Активатор, Модуль активизации) рассматривается в этой главе в разделе, посвященном удаленному доступу. Чтобы создать экземпляр объекта Customers (Клиенты), мы вызываем конструктор без параметров.

Type *t = a › GetType("01. NetCpp.Acme.Customers"); // Клиенты
Object *customerlnstance = // Объект
Activator::Createlnstance(t); // Активатор

Затем, чтобы вызвать метод GetCustomer, формируем список параметров и используем метод Invoke (Вызвать) экземпляра Methodlnfо. Dynamic\Customer\Debug в папку Dynamic\Debug перед выполнение Dynamic.ехе.

// вызвать метод
Object *arguments [] = new Object*[1]; // новый Объект
int customerld = -1;
arguments[0] = _box(customerld); // параметры
Object *returnType = mi › Invoke(// Вызвать
customerlnstance, arguments); // параметры

Используя методы отражения, мы получаем информацию о типе для каждого поля в возвращаемой структуре. Обратите внимание, что метод GetValue, принадлежащий Fieldlnfо, возвращает данные для конкретного поля в объекте.

if (returnType › GetType() ==
Type::GetType("System.Collections.ArrayList"))
// ("Система.Коллекции.Список массивов")
{
ArrayList *arrayList =
dynamic_cast<ArrayList *>(returnType);
for (int i = 0; i<arrayList › Count; i++) // Счет
{
Type *itemType =
arrayList › get_Item(i) › GetType();
Fieldlnfo *fi [] = itemType › GetFields();
for (int j = 0; j < fi › Length; j++)
{
Object *fieldValue = // Объект
fi[j] › GetValue(arrayList › get_Item(i));
Console::Write(// Запись
"{0, -10} = {1, -15}",
fi[j] › Name, fieldValue); // Имя
}
Console::WriteLine();
}
}

Снова обращаем внимание на то, что в строке System.Collections.ArrayList (Система.Коллекции.Список массивов) для отделения имен использованы точки, а не "двойные двоеточия.

В этом коде не использованы никакие определенные объекты или типы из сборки Customer (Клиент). С целью проиллюстрировать главные принципы, мы применили некоторые знания о сборке, чтобы код был простым. Однако должно быть понятно, как сделать его полностью общим.

Можно сделать шаг вперед и использовать классы, которые генерируют метаданные (в System::Reflection::Emit (Система-Отражение-Генерация)). Можно даже динамически создавать сборку в памяти, а затем загружать и выполнять ее!

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.