Файл: 1_C#_Введение_в_программирование_Уч_пособ_(Марченко-2005).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 1375

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

//Определили делегата для функции SC.FunSC.

//Это собственная статическая функция класса SC. dlgSC = new ClassDlg_2(SC.FunSC);

//А теперь достраиваем делегаты, которые

//не были созданы и настроены в конструкторах

//соответствующих классов.

objDoll_1.dlg2Doll_1 = new ClassDlg_2(objDoll_2.F0Doll_2); objDoll_2.dlg1Doll_2 = new ClassDlg_1(objDoll_1.F2Doll_1);

// Подписали объекты на события.

objDoll_1.eventDoll_1 +=new ClassDlg_2(objDoll_2.F0Doll_2); objDoll_2.eventDoll_2 +=new ClassDlg_2(objDoll_1.F0Doll_1);

//SC будет сообщать о времени!

//И не важно, откуда последует вызов функции.

//Событие в классе objDoll_1 используется для вызова

//статического метода класса SC.

objDoll_1.eventDoll_1 +=new ClassDlg_2(SC.dlgSC);

//Событие в классе objDoll_2 используется для вызова

//статического метода класса SC.

objDoll_2.eventDoll_2 +=new ClassDlg_2(SC.dlgSC);

//Работа с делегатами. objDoll_1.dlg2Doll_1(125);

objDoll_2.dlg1Doll_2(521, “Start from objDoll_2.dlg1Doll_2”);

//Работа с событиями. Уведомляем заинтересованные классы и объекты!

//Что-то не видно особой разницы с вызовами через делегатов. objDoll_1.F1Doll_1(125);

objDoll_2.F2Doll_2(521);

//Отключили часть приемников.

//То есть отказались от получения некоторых событий.

//И действительно. Нечего заботиться о чужом классе.

objDoll_1.eventDoll_1 -= new ClassDlg_2(SC.dlgSC); objDoll_2.eventDoll_2 -= new ClassDlg_2(SC.dlgSC);

// Опять работа с событиями. objDoll_1.F1Doll_1(15); objDoll_2.F2Doll_2(51);

}

}

}

События и делегаты. Различия

Так в чём же разница между событиями и делегатами в .NET?

В последнем примере предыдущего раздела при объявлении события очевидно его строгое соответствие определённому делегату.

public static event System.EventHandler xEvent;

System.EventHandler – это ТИП ДЕЛЕГАТА! Оператор, который обеспечивает процедуру “подписания на уведомление”, полностью соответствует оператору модификации многоадресного делегата. Аналогичным образом дело обстоит и с процедурой “отказа от уведомления”.

BaseClass.xEvent += new System.EventHandler(this.MyFun);

BaseClass.xEvent -= new System.EventHandler(xxx.MyFun);

И это действительно так. За операторными функциями += и -= скрываются методы классов-делегатов (в том числе и класса-делегата System.EventHandler).

Более того. Если в последнем примере в объявлении события ВЫКИНУТЬ ключевое слово event –

public static event System.EventHandler xEvent;

97


и заменить его на:

public static System.EventHandler xEvent;

System.EventHandler – это класс-делегат! То ничего не произойдёт. Вернее, ВСЁ будет происходить, как и раньше! Вместо пары СОБЫТИЕ-ДЕЛЕГАТ будет работать пара ДЕЛЕГАТ-ДЕЛЕГАТ. Таким образом, функционально событие является всего лишь разновидностью класса-делегата, главной задачей которого является обеспечение строгой привязки делегата к соответствующему событию.

Модификатор event вносит лишь незначительные синтаксические нюансы в использование этого МОДИФИЦИРОВАННОГО делегата. Чтобы хоть как-нибудь различать возбудителя и получателя события.

98

Атрибуты, сборки, рефлексия

Рефлексия (отражение) типов

Процесс анализа типов (структуры типов) в ходе выполнения приложения (сборки). В .NET реализуется при помощи класса System.Type и пространства имён System.Reflection.

reflection - система, предоставляющая выполняемому коду информацию о нем самом.

Пространство имён System.Reflection содержит классы и интерфейсы, которые позволяют организовать просмотр загруженных в сборку типов, методов, полей (данных-членов), и обеспечивают динамические механизмы реализации типов и вызова методов. Включает множество взаимосвязанных классов, интерфейсов, структур и делегатов, предназначенных для реализации процесса отражения. Неполный перечень классов представлен ниже:

Тип

Назначение

 

Assembly

Методы для загрузки, описания и выполнения разнообразных операций

 

над сборкой.

 

AssemblyName

Информация о

сборке (идентификатор, версия, язык реализации).

EventInfo

Информация о

событиях.

FieldInfo

Информация о

полях.

MemberInfo

Абстрактный

базовый класс, определяющий общие члены для

 

EventInfo, FieldInfo, MethodInfo, PropertyInfo.

MethodInfo

Информация о

методе.

Module

Позволяет обратиться к модулю в многофайловой сборке.

ParameterInfo

Информация о

параметре.

PropertyInfo

Информация о

свойстве.

Класс System.Type содержит методы, позволяющие получать информацию о типах приложения, пространства имён System.Reflection определяет типы для организации позднего связывания и динамической загрузки типов.

Класс Type является основой для реализации функциональности System.Reflection и средством для получения доступа к метаданным.

Использование членов класса Тип, позволяет получить информацию о:

типе (GetType(string)),

конструкторах (GetConstructors()),

методах (GetMethods()),

данных-членах (GetFields()),

свойствах (GetProperties()),

событиях, объявленных в классе (GetEvents()),

модуле,

сборке, в которой реализуется данный класс.

Объект-представитель класса Type уникален. Две ссылки на объектыпредставители класса Type оказываются эквивалентными, если только они были построены в результате обращения к одному и тому же типу.

Объект-представитель класса Type может представить любой из следующих типов:

Классы

Размерные типы

Массивы

Интерфейсы

Указатели

Перечисления

Ссылка на объект-представитель класса Type, ассоциированная с некоторым типом, может быть получена одним из следующих способов:

1. В результате вызова метода

Type Object.GetType()

(метода-члена класса Object), который возвращает ссылку на объектпредставитель типа Type, представляющий информацию о типе. Вызов производится

99


от имени объекта-представителя данного типа. Вызов становится возможен в связи с тем, что любой класс наследует тип Object.

2. В результате вызова статического метода-члена класса Type:

public static Type Type.GetType(string)

Параметром является строка со значением имени типа. Возвращает объектпредставитель класса Type, с информацией о типе, специфицированном параметром метода.

3. От имени объекта-представителя класса Assembly - от имени объекта-сборки (самоописываемого, многократно используемого, версифицируемого БЛОКА (фрагмента) CLR-приложения) вызываются методы

Type[] Assembly.GetTypes()

Type Assembly.GetType(string)

//Получаем ссылку на сборку, содержащую объявление типа MyType,

//затем – массив объектов-представителей класса Type.

Type[] tt = (Assembly.GetAssembly(typeof(MyType))).GetTypes(); // Без комментариев.

Type[] tt = (Assembly.GetAssembly(typeof(MyType))).GetType(“MyType”);

От имени объекта-представителя класса Module (Модуль - portable executable файл с расширением .dll или .exe, состоящий из одного и более классов и интерфейсов)

Type[] Module.GetTypes() Type Module.GetType(string)

Type[] Module.FindTypes(TypeFilter filter, object filterCriteria)

где TypeFilter – класс-делегат

//The TypeFilter делегаты используются to filter списка классов.

//А как этим хозяйством пользоваться - не знаю. В хелпах не нашёл. public delegate bool TypeFilter(Type m, object filterCriteria);

4. В результате выполнения операции typeof(), которая применяется для построения объекта-представителя класса System.Type. Выражение, построенное на основе операции typeof, имеет следующий вид:

typeof(type)

Операнд выражения – тип, для которого может быть построен объектпредставитель класса System.Type.

Пример применения операции:

using System;

using System.Reflection;

public class MyClass

{

public int intI; public void MyMeth()

{

}

public static void Main()

{

Type t = typeof(MyClass);

//Альтернативная эквивалентная конструкция

//MyClass t1 = new MyClass();

//Type t = t1.GetType();

MethodInfo[] x = t.GetMethods(); foreach (MethodInfo m in x)

{

Console.WriteLine(m.ToString());

}

Console.WriteLine();

MemberInfo[] x2 = t.GetMembers(); foreach (MemberInfo m in x2)

{

100



Console.WriteLine(m.ToString());

}

}

}

Реализация отражения. Type, InvokeMember, BindingFlags

Раннее связывание – деятельность, выполняемая на стадии компиляции, позволяющая:

обнаружить и идентифицировать объявленные в приложении типы,

выявить и идентифицировать члены класса,

подготовить при выполнении приложения вызов методов и свойств, доступ к значениям полей-членов класса.

Позднее, динамическое связывание – деятельность, выполняемая непосредственно при выполнении приложения, позволяющая:

обнаружить и идентифицировать объявленные в приложении типы,

выявить и идентифицировать члены класса,

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

При этом вызов методов и свойств при выполнении приложения обеспечивается методом InvokeMember. Этот метод выполняет достаточно сложную работу и поэтому нуждается в изощрённой системе управления, для реализации которой применяется перечисление BindingFlags. Перечисление также применяется для

управления методом GetMethod.

 

 

 

 

 

 

 

В рамках этого

перечисления определяются значения флажков, которые

управляют процессом динамического связывания в ходе реализации отражения.

Список элементов перечисления прилагается.

 

 

 

 

 

Имя элемента

Описание

 

 

 

 

 

 

 

CreateInstance

Определяет,

что

отражение

должно создавать

экземпляр

 

 

заданного

типа.

Вызывает

конструктор,

соответствующий

 

 

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

 

 

обрабатывается. Если тип поиска не указан, будут использованы

 

 

флаги (Instance | Public). Инициализатор типа вызвать нельзя.

 

DeclaredOnly

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

 

 

объявленные на уровне переданной иерархии типов. Наследуемые

 

 

члены не учитываются.

 

 

 

 

 

Default

Определяет отсутствие флагов связывания.

 

 

 

 

 

Определяет, что типы представленных аргументов должно точно

 

ExactBinding

 

 

соответствовать типам соответствующих формальных параметров.

 

 

Если вызывающий оператор передает непустой объект Binder,

 

 

отражение создает исключение, так как при этом вызывающий

 

 

оператор предоставляет реализации BindToXXX, которые выберут

 

 

соответствующий метод.

 

 

 

 

 

 

Отражение моделирует правила доступа для системы общих типов.

 

 

Например, если вызывающий оператор находится в той же сборке,

 

 

ему не нужны специальные разрешения относительно внутренних

 

 

членов. В противном случае вызывающему оператору потребуется

 

 

ReflectionPermission. Этот метод применяется при поиске

 

 

защищенных, закрытых и т. п. членов.

 

 

 

 

 

Главный принцип заключается в том, что ChangeType должен

 

 

выполнять только расширяющее преобразование, которое никогда

 

 

не теряет данных. Примером расширяющего преобразования

 

 

является преобразование 32-разрядного целого числа

со

знаком

 

 

в 64-разрядное целое число со знаком. Этим оно отличается от

 

 

сужающего преобразования, при котором возможна потеря данных.

 

 

Примером сужающего преобразования является преобразование 64-

 

 

разрядного целого числа со знаком в 32-разрядное целое число

 

 

со знаком.

 

 

 

 

 

 

 

 

Связыватель по умолчанию не обрабатывает этот флаг, но

 

 

пользовательские

связыватели

используют

семантику

этого

 

 

флага.

 

 

 

 

 

 

 

FlattenHierarchy

Определяет, что должны быть

возвращены

статические

члены

 

 

вверх по иерархии. Статические члены — это поля, методы,

 

 

события и свойства. Вложенные типы не возвращаются.

 

 

 

101