Файл: 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