Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Учебное пособие 1082

.pdf
Скачиваний:
4
Добавлен:
30.04.2022
Размер:
753.13 Кб
Скачать

Console.WriteLine ("***** Свойства *****");

// здесь полная информация о свойстве

Propertylnfo [ ] pi = t.GetProperties();

var propNames = from p in t.GetProperties() select p.Name;

foreach (var name in propNames) Console.WriteLine ("->{0}", name);

Console.WriteLine ();

}

Метод GetInterfaces() возвращает сведения об интерфей-

сах

var im = t.GetInterfaces();

GetInterfaces() возвращает массив System.Types, по-

скольку интерфейсы в действительности представляют собой типы.

В примере метод ListInterfaces() отображает имена поддерживаемых указываемым типом интерфейсов.

// Отображение имен реализуемых интерфейсов static void ListInterfaces(Type t)

{

Console.WriteLine ("***** Интерфейсы*****");

var ifaces = from i in t.Getlnterfaces() select i; foreach(Type i in ifaces)

Console.WriteLine ("->{0 } ", i.Name);

}

Можно получить дополнительную информацию о типе, используя метод

static void ListVariousStats(Type t)

{

Console.WriteLine ("***** Дополнительная информация *****");

// Базовый класс

Console.WriteLine("Базовым классом является: {0}", t.BaseType);

// Абстрактный?

19

Console.WriteLine("Тип абстрактный? {0}",

t.IsAbstract);

// Запечатанный?

Console.WriteLine("Тип запечатанный? {0}",

t.IsSealed);

// Обобщённый?

Console.WriteLine("Тип обобщенный? {0}",

t. IsGenericTypeDefinition);

// Класс?

Console.WriteLine ("Тип является классом? {0}",

t.IsClass);

Console.WriteLine();

}

Рассмотрим пример, в котором метод Main() запрашивает у пользователя полное уточненное имя типа, передает его методу Туре.GetType() и вызывает все представленные выше методы.

Пользователь вводит имя типа или Q для завершения работы приложения.

static void Main()

{

Console.WriteLine("***** Просмотр типов *****);

string typeName = ""; do {

Console.WriteLine ("\nВведите имя типа для определения”);

// Запрос имени типа или признака выхода

Console.Write(“ или наберите Q для выхода”);

// Получение имени типа

typeName = Console.ReadLine();

// Пользователь может выйти из программы if (typeName.ToUpper() == "Q" )

break;

// Отобразить информацию о типе

20

try

{

Type t = Type.GetType(typeName); Console.WriteLine(""); ListVariousStats(t);

ListFields(t);

ListProps(t);

ListMethods(t);

ListInterfaces(t);

}

catch

{

Console.WriteLine (“Такой тип не найден”); // Указанный тип не найден

}

}

while (true);

}

Рефлексия обобщенных типов

При вызове Туре.GetType() для получения описаний метаданных обобщённых типов должен обязательно применяться специальный синтаксис – символ обратной одинарной кавычки (`) со следующим за ним числовым значением, которое представляет количество параметров, поддерживаемое типом

[3].

Чтобы отобразить описание метаданных обобщенного

типа

System.Collections.Generic.List<T>

надо передать следующую строку

System.Collections.Generic.List`1

Здесь используется числовое значение 1, поскольку List<T> имеет только один параметр.

Для применения рефлексии типа

Dictionary<TKey, Tvalue>

надо указать значение 2:

21

System.Collections.Generic.Dictionary`2

Динамически загружаемые сборки

Рассмотрим метод Main(), который будет запрашивать у пользователя имя сборки для ее динамической загрузки.

Ссылка на эту сборку передается методу DisplayTypes(), который выводит имена всех содержащихся в сборке классов, интерфейсов, структур, перечислений и делегатов.

static void DisplayTypesInAsm(Assembly asm)

{

Console.WriteLine ("***** Типы в сборке *****");

Console.WriteLine("->{0}", asm.FullName); Type [ ] types = asm.GetTypes();

foreach (Type t in types) Console.WriteLine("Type: {0}", t) ;

Console.WriteLine( );

}

static void Main()

{

Console.WriteLine (“***** Внешняя сборка *****”);

string asmName = “”;

Assembly asm = null; do

{

Console.WriteLine(“Имя сборки или Q для выхода “); asmName = Console.ReadLine();

if (asmName.ToUpper() == "Q") break;

try

{

asm = Assembly.LoadFrom(asmName); DisplayTypesInAsm(asm);

}

catch

{

Console.WriteLine(“Сборка не найдена ");

22

}

}

while (true);

}

Методу Assembly.LoadFrom() передается только дружественное имя сборки, которую требуется загрузить в память.

Поэтому сначала надо скопировать двоичный файл в подкаталог bin\Debug приложения.

Позднее связывание

Поздним связыванием (late binding) называется техноло-

гия, которая позволяет создавать экземпляр определенного типа и вызывать его члены во время выполнения, а не на этапе компиляции [1 - 3].

Класс System.Activator (сборка mscorlib.dll) играет клю-

чевую роль в процессе позднего связывания в .NET.

Его метод Activator.CreateInstance() позволяет создавать экземпляр, подлежащий позднему связыванию типа.

В простой версии CreateInstance() принимает действительный объект Туре, описывающий сущность, которая должна размещаться в памяти при выполнении программы.

Пример – приложение загружает внешнюю сборку и создаёт объект за счёт применения позднего связывания.

static void Main()

{

Console.WriteLine ("***** Позднее связывание *****");

Assembly a = null; try

{

a = Assembly.LoadFrom("Shapes.dll");

}

catch(FileNotFoundException ex)

{

Console.WriteLine(ex.Message);

23

return;

}

if (a != null) CreateUsingLateBinding(a);

}

static void CreateUsingLateBinding(Assembly a)

{

try

{

Type circ = a.GetType("Shapes.Circle"); object obj = Activator.Createlnstance(circ);

Console.WriteLine("Создан {0} в динамике", obj);

}

catch(Exception ex)

{

Console.WriteLine(ex.Message);

}

}

Метод Activator.CreateInstance() возвращает экземпляр объекта System.Object, а не строго типизированный объект.

Явное приведение к типу Circle

object obj = (Circle)Activator.Createlnstance(circ);

вызовет синтаксическую ошибку.

Смысл позднего связывания состоит в создании экземпляров объектов, о которых при компиляции не известно.

Вызов методов Circle обеспечивает рефлексия.

Напрмер, для метода Area() имеем объект MethodInfo

после вызова Type.GetMethod().

После получения объекта MethodInfo можно вызвать и сам obj.Area(), воспользовавшись Invoke().

Метод MethodInfo.Invoke() ожидает всех параметров в виде массива System.Object, т.к. эти параметры могут быть самыми разными сущностями.

В примере метод Area() не требует никаких параметров, поэтому методу Methodlnfo.Invoke() надо передать значение null

24

MethodInfo mi = circ.GetMethod("Area"); double areaCircle =(double)mi.Invoke(obj, null);

Console.WriteLine("Площадь круга=" + areaCircle);

ЗАДАНИЕ

1.По аналогии с примером из теоретического раздела исследовать типы:

int,

double,

char,

string,

StringBuilder,

Array,

ArrayList,

System.IO.BinaryWriter,

System.Math,

System.Console,

XXXXXXX.Program.

2.Создать библиотеку (*.dll), представляющую иерархию классов:

средство передвижения (абстрактный класс),

автомобиль,

велосипед,

легковой автомобиль.

Вклассах предусмотреть по 3 конструктора, по 2-3 свойства, по 2-3 метода, показывающих информацию о средстве передвижения, определяющих, находится ли в рабочем состоянии средства, местоположение средства передвижения. Выполнить проект, проверить правильность результатов.

3. Исследовать сборку с созданной библиотекой классов (все классы и их содержимое).

4. Создать динамически объект любого класса создан-

ной библиотеки и вызвать два его метода.

25

КОНТРОЛЬНЫЕ ВОПРОСЫ

1.Как извлечь информацию о полях, свойствах, интерфейсах из сборки?

2.Как проводится рефлексия обобщенных типов?

3.Что такое позднее связывание?

4.Как создать объект при позднем связывании?

5.Как вызвать метод динамически созданного объекта?

СОДЕРЖАНИЕ И ПОРЯДОК ВЫПОЛНЕНИЯ РАБОТЫ

Ознакомиться с теоретическими сведениями, ответить на контрольные вопросы. По заданиям разработать приложения. Составить отчет.

26

РАБОТА № 4

ПРОЦЕССЫ, ДОМЕНЫ ПРИЛОЖЕНИЙ, ПОТОКИ

Цель работы: изучение техники работы с процессами, потоками, доменами приложений.

ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ

Домен приложения (Application Domain – AppDomain) –

логический раздел в отдельном процессе, где обслуживается набор связанных между собой сборок .NET [1 – 4].

Вдомене приложения существуют контекстные границы (context boundaries), применяемые для группировки подоб- ных .NET-объектов.

Важно понимание данных технологий при:

– работе с API-интерфейсами .NET (Windows Communication Foundation – WCF),

– многопоточной обработке,

– параллельной обработке,

– сериализации объектов.

Водном процессе обычно обслуживается 1 домен приложения, хотя их может обслуживаться и более.

Влюбом процессе ОС всегда обслуживает домен приложения по умолчанию (default application domain).

Этот домен создается автоматически CLR во время запуска процесса.

После создания домена по умолчанию CLR создает все остальные дополнительные домены приложений по мере необходимости.

ВSystem.Diagnostics представлен набор типов для программного взаимодействия с процессами и системным журналом событий.

27

Класс System.Diagnostics.Process позволяет анализиро-

вать процессы, которые выполняются на какой-то определенной машине (локальной или удаленной).

Члены класса (табл. 3) позволяют программно запускать и останавливать процессы, просматривать приоритет процесса, а также получать список активных потоков.

 

Таблица 3

 

 

 

Метод

Описание

 

 

 

 

CloseMainWindow()

Завершает процесс, обладающий поль-

 

 

зовательским интерфейсом, за счёт от-

 

 

правки в его главное окно сообщения о

 

 

закрытии

 

GetCurrentProcess()

Статический метод, возвращает новый

 

 

объект Process - активный процесс в

 

 

текущий момент

 

GetProcesses()

Статический метод, возвращает массив

 

 

новых объектов Process, которые вы-

 

 

полняются на текущей машине

 

Kill()

Немедленно останавливает процесс

 

 

 

 

Start()

Запускает процесс

 

 

 

 

Пример работы с объектами Process.

public static void ListAllRunningProcesses()

{

//процессы, выполняющиеся на текущей машине (“.”),

//упорядоченные по PID

var runmngProcs = from proc in Process.GetProcesses(“.") orderby proc.Id

select proc;

28