Мегаобучалка Главная | О нас | Обратная связь


Внутренний механизм поддержки событий



2016-01-26 324 Обсуждений (0)
Внутренний механизм поддержки событий 0.00 из 5.00 0 оценок




Лабораторная работа № 12.2

 

Тема:Разработка программ реализующих паттерн наблюдатель при помощи механизма событий.

Цель работы: Формирование умений и навыков использования событий в программе.

 

Время на выполнение работы: 2 часа

Этапы работы:

I.Ознакомится с теоретическими сведениями

II.Выполнить задания.

III.Ответить на контрольные вопросы

 

I Теоретические сведения

Как устроены события и зачем они нужны

Начнем изучение с несколько идеализированного примера. Допустим, имеется некоторый компонент, и пускай для упрощения примера это будет банальная кнопка. Всем известно, что на кнопки можно нажимать. При нажатии кнопки происходит событие "щелчок", о котором необходимо обязательно уведомлять пользователя нашего компонента. Для этого введем в класс, представляющий компонент-кнопку, общедоступное поле Click, являющееся экземпляром делегата. И каждый раз, когда будет происходить соответствующее событие, будем обращаться к этому делегату. А он, в свою очередь, будет вызывать прикрепленные к нему функции и методы. Приведу код (листинг 11).

Листинг 11. Пример события на основе делегата.

// Введем специальный делегат. delegate void ClickHandler();   class Button { // Это общедоступное поле-делегат, к которому каждый // может присоединить собственный метод. public ClickHandler Click; // Несколько идеализированная функция обработки // сообщений, приходящих на кнопку. void OnMsg(...) { // Предположим switch(msg) { // Вот мы как бы засекли нажатие на кнопку. case WM_LBUTTONDOWN: // Вызовем функции, связанные с нашим делегатом, // предварительно проверив, а зарегистрирована // ли хотя бы одна функция в поле-делегате. if (Click != null) Click(); } };

Теперь пользователи нашего класса смогут присоединить свои функции к переменной-полю экземпляра делегата и получить уведомление о произошедшем событии.

Но поскольку среда .NET является объектно-ориентированной, мы обязаны соблюдать правила инкапсуляции полей. Соответственно, необходимо ввести дополнительные методы, обслуживающие поле-экземпляр делегата и контролирующие все производимые над ним операции, а само поле полагается сделать закрытым. Сделаем это следующим образом — добавим две функции add_Click и remove_Click, которые, соответственно, будут добавлять и убирать события в очередь делегата. Новый код представлен в листинге 12.

Листинг 12. Пример события на основе делегата, с поддержкой инкапсуляции полей.

// Введем специальный делегат. delegate void ClickHandler(); class Button { // Поле-делегат, к которому будут присоединяться обработчики // нажатия кнопки. // Обратите внимание, это поле теперь является закрытым, // оно недоступно извне класса. private ClickHandler Click; // Введем два общедоступных метода, // которые будут предоставлять сервисы работы с событием. public add_Click(ClickHandler delegate) { // Воспользуемся удобным арифметическим оператором // для комбинирования делегатов. Click += delegate; } // Удаление функции из списка вызова. public remove_Click(ClickHandler delegate) { // Удалим функции, представленные делегатом. // delegate из нашего списка вызовов Click -= delegate; } // Несколько идеализированная функция обработки // сообщений, приходящих на кнопку. void OnMsg(...) { // Предположим. switch(msg) { // Вот мы как бы засекли нажатие кнопки. case WM_LBUTTONDOWN: // Вызовем функции, связанные с нашим делегатом, // предварительно проверив, а зарегистрирована // ли хотя бы одна функция в поле-делегате. if (Click != null) Click(); } };

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

События .NET

Понимали это и разработчики, создававшие среду .NET. Для решения этой задачи они ввели специальное поле-событие, которое автоматически вводит поле-делегат и два дополнительных метода, обслуживающих его. Таким образом, автоматически реализуется представленная выше модель.

В языке высокого уровня C# определение таких полей осуществляется при помощи ключевого слова event. Также компилятор берет на себя заботу о работе с этими полями-событиями, благодаря чему к ним можно прибавлять и вычитать делегаты, хотя они, по сути дела, таковыми не являются. Приведем наглядный пример использования полей-событий (листинг 13).

Листинг 13. Использование полей-событий.

using System; // Введем собственный делегат, не принимающий // никаких значений. delegate void MyDelegate(); // Это тестовый класс, он представляет собой гипотетический // компонент кнопки. class Button { // Введем общедоступное событие, к которому // смогут подключаться все желающие. public event MyDelegate Click; // Данная функция необходима для того, чтобы // симулировать событие нажатия на кнопку. public void SimulateClick() { // Вызываем функции, связанные с событием Click, // предварительно проверив, зарегистрировался // ли кто-нибудь в данном событии. if (Click != null) Click(); } };   class App { static void Main() { // Создаем экземпляр класса/компонента. Button sc = new Button(); // Добавляем обработчик к его событию. sc.Click += new MyDelegate(Handler); // Сами вызовем функцию, которая инициирует // возникновение события нажатия на кнопку. sc.SimulateClick(); } // А это функция-обработчик события нажатия на кнопку. static void Handler() { Console.WriteLine("Hello, World!"); } };

В результате работы приложения, на консоль будет выведена следующая строка:

Hello, World!

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

Внутренний механизм поддержки событий

Рассмотрим, какой код поддержки события был создан компилятором. Для этого изучим IL- код.

Во-первых, компилятор создал поле-делегат, в котором хранятся все зарегистрированные обработчики события.

.field private class MyDelegate Click

Обратите внимание, что поле является закрытым и может быть использовано только из самого класса, исключая даже его потомков (private). Также компилятор создал одноименное специализированное свойство, в котором указаны методы, реализующие внешнюю работу с данным событием. Причем необходимо отметить, что это свойство по умолчанию является общедоступным.

.event MyDelegate Click { .addon instance void Button::add_Click(class MyDelegate) .removeon instance void Button::remove_Click(class MyDelegate) }

Дабы не утомлять читателя излишним чтением IL-листингов, приведем код методов на языке C#.

public void add_Click(MyDelegate del) { Click += del; } public void remove_Click(MyDelegate del) { Click -= del; }

Методы будут использоваться только при работе с событием извне класса. Внутри же используется прямое обращение к полю Click, что несколько быстрее, чем вызов методов add_Click и remove_Click. Здесь можно усмотреть борьбу команды разработчиков компилятора С# за производительность создаваемых им программ.

Чтобы подтвердить сказанное, приведем IL-код функции SimulateClick, которая непосредственно обращается к событию из самого класса, если быть до конца точным, то не к самому событию, а к полю-экземпляру делегата.

.method public hidebysig instance void SimulateClick() cil managed { .maxstack 1 ldarg.0 // Загружаем в стек указатель на интересующее нас поле. ldfld class MyDelegate Button::Click brfalse.s IL_0013 ldarg.0 // Загружаем в стек указатель на интересующее нас поле. ldfld class MyDelegate Button::Click callvirt instance void MyDelegate::Invoke() ret }

Обратите внимание на выделенную в коде инструкцию ldfld — она предназначена для работы с полями объекта. Также в листинге отсутствуют обращения к функциям add_Click и remove_Click. Что и требовалось доказать!



2016-01-26 324 Обсуждений (0)
Внутренний механизм поддержки событий 0.00 из 5.00 0 оценок









Обсуждение в статье: Внутренний механизм поддержки событий

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Личность ребенка как объект и субъект в образовательной технологии: В настоящее время в России идет становление новой системы образования, ориентированного на вхождение...
Почему люди поддаются рекламе?: Только не надо искать ответы в качестве или количестве рекламы...
Генезис конфликтологии как науки в древней Греции: Для уяснения предыстории конфликтологии существенное значение имеет обращение к античной...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (324)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.007 сек.)