|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Відключення
обробників подій
Обробники подій, що
динамічно призначаються командою Addhandler, відключаються командою Removehandler, якою
повинні передаватися такі самі аргументи, як і при відповідному виклику Addhandlеr.
Зазвичай для видалення обробників, що динамічно призначаються, добре
підходить метод Dispose. З цієї причини в кожному класі, що використовує
динамічне призначення обробників, рекомендується реалізувати інтерфейс Idisposable
— це нагадає користувачам класу про необхідність виклику Dispose.
Обробка
подій в ієрархії спадкоємства
Похідний
клас може у будь-який момент ініціювати відкриті або захищені події свого
базового класу, при цьому подія ідентифікується ключовим словом Mybase.
Крім того, похідні класи автоматично успадковують всі обробники відкритих
і захищених подій своїх предків. Час від часу в похідному класі виникає
необхідність в перевизначенні методів, використовуваних при обробці відкритих
і захищених подій базового класу. Для цієї мети використовується конструкція
Handles Mybase. Приклад: Public
Class Parentclass Public Event Parenteventtbyval athing As Object. Byval E As System.EventArgs) '
Програмний код End Class ' Похідний клас Public
Class Childclass Inherits
Parentclass Sub Eventhandler(Byval x As Integer) Handles Mybase Parentevent 'Обробка
подій базового класу End Sub End Class
При використанні механізму зворотного
виклику доводиться виконувати допоміжні операції для реєстрації функцій,
що викликаються. У частині, що залишилася, розділи буде показано, що
при цьому відбувається і як за допомогою цих операцій добитися максимальної ефективності
зворотного виклику. Механізм зворотного
виклику (а отже, і події) в VB .NET залежить від особливого різновиду об'єктів
.NET, званих делегатами. Делегат є екземпляром класу System.Delegate.
У простому випадку в делегатові інкапсулюється об'єкт і адреса заданої
функції або процедури цього об'єкту. Такі делегати ідеально підходять для
схем зворотного виклику на зразок тієї, що використовується при обробці подій.
Чому? Тому що делегат містить всю інформацію, необхідну для зворотного
виклику, і може використовуватися для виклику потрібного методу об'єкту-приймача. Але перш,
ніж переходити до опису роботи з делегатами, варто підкреслити одну важливу
обставину. Хоча обробка подій на платформі .NET заснована на використанні
делегатів, в переважній більшості випадків вам не доведеться працювати безпосередньо
з делегатами. Команда Addhandl ег надає у ваше розпорядження все
необхідне для гнучкої обробки подій в VB .NET (втім, як ви незабаром побачите,
у делегатів є і інші застосування). Таким
чином, довільні покажчики на функції володіють принциповим недоліком:
компілятор не може перевірити, що такий покажчик відноситься до функції правильного
типу. Делегати є різновидом покажчиків на функції, безпечних по
відношенню до типів. Слідуючи принципу «довіряй, але перевіряй», компілятор автоматично
перевіряє сигнатуру функції, що викликається, — такий варіант працює
набагато надійніше.
Почнемо із створення простого делегата, що
інкапсулює об'єкт і «покажчик» на процедуру цього
об'єкту. Як показано нижче, синтаксис створення об'єктів трохи складніший за синтаксис,
використовуваний при створенні простих об'єктів. Перш за все нам
знадобиться клас, що містить процедуру з певною сигнатурою: Class
Classforstringsubdelegate '
Використовувати конструктор за умовчанням Public Sub Testsub(Byval astring As String) Console. Writeline(astring
Sastring) End Sub End
Class Щоб створити
делегат для зворотного виклику цієї процедури, необхідно повідомити компілятор
про використання делегата для процедури з одним строковим параметром. Перший
крок цього сценарію виконується за межами Sub Main наступним рядком: Public Delegate Sub Stringsubdelegate(Byval astring As String) Звернете
увагу: у цьому рядку ми не оголошуємо делегат, а визначаємо його. Компілятор
VB .NET автоматично створює новий клас Stringsubdel egate, похідний від
System . Delegate1. Далі в процедурі Sub
Main екземпляр класу делегата створюється оператором Addressof для адреси процедури,
що має правильну сигнатуру. VB .NET автоматично обчислює об'єкт
по повному імені процедури. Команда створення екземпляра виглядає так: adel egate =
Addressof test.TestSub Компілятор
VB .NET розуміє, що делегат створюється для об'єкту test. Також можна скористатися
ключовим словом New, проте це робиться рідко, оскільки New неявно викликається
в першій формі: adelegate =
New Stringsubdelegate(Addressof test.TestSub) Після того,
як делегат буде створений, інкапсульована в нім процедура викликається методом
Invoke класу Delegate, як в наступному фрагменті: Sub Main( ) Dim test As
New Classforstri ngsubdelegate() Dim
adelegate As Stringsubdelegate adelegate =
Addressof test.TestSub adelegate.Invoke(
"Hello" ) Console. Readlineb End Sub У цьому неважко
переконатися, проглядаючи отриманий IL-код за допомогою програми ILDASM. Погодитеся,
такий спосіб виводу в консольному вікні рядка «Hellohello» виглядає
декілька незвично! Втім,
«якщо це і безумство, то у своєму роді послідовне». Припустимо,
ви вирішили удосконалити свій клас, щоб замість простого виведення тексту
в консольному вікні на екрані з'являлося вікно повідомлення. Для цього досить
внести зміни, виділені жирним шрифтом в наступному лістингу: Module
Modulel Public Delegate Sub Stringsubdelegate(Byval astring As String) Sub Main() Dim test As
New Classforstringsubdelegate() Dim
adelegate As Stringsubdelegate adelegate -
Addressof test.TestMsgBox adelegate("Hello") Console. Readline() End
Sub Class
Classforstringsubdelegate ' Використовувати конструктор за умовчанням Public Sub Testsub(Byval
astring As String) Console.WriteLine(astring Sastring) End
Sub Public Sub Testmsgbox(Byval
astring As String) Msgbox(astring &aString) End
Sub End Class End
Module Оскільки для
делегата важлива тільки сигнатура інкапсульованого методу, він легко «перемикається» на
інший метод. Потрібно було створити нову версію для виведення інформації у
вікні відладки (замість консолі і вікна повідомлення)? Досить внести декілька
змін делегат і додати в клас функцію, що інкапсулюється делегатом. Найважливіша
особливість делегатів полягає в тому, що пов'язання з методом проводиться
на стадії виконання. Таким чином, делегати у поєднанні з явним або
неявним викликом методу Invoke по своїх можливостях значно перевершують
функцію Vb6 Callbyname.
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||