Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

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

События

MulticastDelegate.CreateDelegate

Метод позволяет динамически создать делегат заданного типа.

public static Delegate Delegate.CreateDelegate(Type type, MethodInfo method);public static Delegate Delegate.CreateDelegate(Type type, Object target, string method);public static Delegate Delegate.CreateDelegate(Type type, Type target, String method);public static Delegate Delegate.CreateDelegate(Type type, Object target, String method, bool ignoreCase);

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

"Нулевые делегаты"

При программировании делегатов может создаться впечатление, что существуют так называемые нулевые делегаты. Под нулевыми делегатами подразумеваются экземпляры классов делегатов, не содержащие ссылок на методы. Такой делегат можно попытаться получить, изъяв из списка все методы, на которые он ссылается при помощи функции Remove. В коде это будет выглядеть так.

del = new MyDelegate(SomeMethod);del -= new MyDelegate(SomeMethod);

И если до исполнения инструкции делегат ссылался на один метод SomeMethod, то в результате ее исполнения мы должны получить пустой делегат. На самом деле, мы получаем нулевую ссылку, то есть просто null. Что, кстати говоря, неочевидно, поскольку мы и далее имеем переменную del, которая подразумевает под собой ссылку на экземпляр делегата.

Большинство программистов попросту не ожидают такого подвоха со стороны системы и попадаются в коварную ловушку — они пытаются использовать методы данного экземпляра делегата. А поскольку он равен null, то происходит исключение NullReferenceException. Для того чтобы избежать подобных ошибок, в неоднозначных местах программы необходимо обязательно проверять значение делегата на null. Делается это следующим образом.

if (del!= null) del("Hello, World!\n");

Во всех случаях, когда значение делегата не известно со стопроцентной уверенностью, такая проверка обязательно должна присутствовать. Это позволит вам избежать очень неприятных ошибок.

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

Начнем изучение с несколько идеализированного примера. Допустим, имеется некоторый компонент, и пускай для упрощения примера это будет банальная кнопка. Всем известно, что на кнопки можно нажимать. При нажатии кнопки происходит событие "щелчок", о котором необходимо обязательно уведомлять пользователя нашего компонента. Для этого введем в класс, представляющий компонент-кнопку, общедоступное поле 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(); }};

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

<== предыдущая лекция | следующая лекция ==>
MulticastDelegate.GetInvocationList | События .NET
Поделиться с друзьями:


Дата добавления: 2014-01-07; Просмотров: 321; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.009 сек.