|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Групові
делегати
У приведених
вище прикладах в делегатові інкапсулювалася адреса однієї функції або процедури.
Нерідко в делегатах потрібно інкапсулювати відразу декілька процедур (інкапсуляція
декількох функцій особливого сенсу не має — яким має бути повертане
значення?). Подібні делегати називаються груповими (multicast) і реалізуються
у вигляді делегата, що містить декілька однотипних делегатів. За наявності
групового делегата всі інкапсульовані процедури викликаються одним методом Invoke,
причому це відбувається відповідно до порядку занесення їх делегатів в груповий
делегат. Щоб створити
груповий делегат, слід об'єднати мінімум двох делегатів одного типу і привласнити
результат змінної того ж типу. Завдання вирішується статичним методом Combine
класу System.Delegate, який повертає новий делегат. Допустимо, firstdel і secdel — екземпляри класу Mymulticastdelegate. Наступна команда об'єднує firstdel і secdel в груповий делегат, що зберігається в firstdel: firstdel
=System.Delegate.Combine(firstdel,secdel) Нижче приведено
просте застосування, об'єднуюче адреси декількох функцій в груповому делегатові: 1 Option
Strict On 2 Module
Modulel 3 Sub Main() 4 Console.WriteLine("Calling
delegate function...") 5 Registerdelegate(Addressof
Callbackhandlerl) 6 Registerdelegate(Addressof
Callbackhandler2) 7 Call Delegates
() 8 Console.WriteLine( 9 "Finished
calling.delegate function...") 10 Console.ReadLine() 11 End
Sub 12 Public Sub
Callbackhandlerhbyval lngval As RETURNJALUES) 13 Console.WriteLine("Callback
1 returned " & Ingval) 14 End
Sub 15 Public Sub
Callbackhandler2(Byvallngval As RETURNJALUES) 16 Console.WriteLine("Callback
2 returned " & Ingval) 17 End
Sub 18 End
Module 19
Module Module2 20 Public Delegate
Sub Callbackfunc(Byvallngvalas Return_values) 21
Private m_cbfunc As Callbackfunc 22
Public Enum Return_values 23
Value_success 24
Value_failure 25 End
Enum 26 Public Sub
Registerdelegate(Byref cbfunc As Callbackfunc) 27 m_cbfunc
= Ctype(System.Delegate.Combine(_ 28 m_cbfunc.cbFunc).CallBackFunc) 29 End
Sub 30 Public Sub
Call Delegates () 31 Dim
Ingcounter As Long = 0 32 '
Викликати процедури через делегата 33 ' і
повернути ознаку успішного виклику 34 m_cbfunc(RETURN
VALUES.VALUE_SUCCESS) 35 End
Sub 36 End Module У рядках 5 і 6 викликається процедура модуля Module2 (рядки 26-28), де і відбувається фактична побудова групового делегата. Це можливо завдяки тому, що делегат передається по посиланню, а не за значенням. Звернете увагу на перетворення типу методу Combine до типу делегата в рядку 27. Безпосередній виклик функцій групового делегата відбувається в рядках 30-35. Всім зареєстрованим функціям передається значення перераховуваного типу RETURNJALUES . Value_success. Результат виконання програми показаний на малюнку.
Групові
делегати як члени класів
У попередньому прикладі
всі модулі мають доступ до всіх функцій решти модулів. Таку архітектуру не
можна визнати вдалою — правильніше було б оформити делегат у вигляді члена класу,
ніж у вигляді відкритого об'єкту. Це дозволить виконати перед його створенням
перевірку, аналогічну тій, яка виконується для інших членів класу. Нижче
приведений злегка змінений варіант предиду- щів архітектури,
де перед доповненням групового делегата новими функціями виконується перевірка
(у даному прикладі — вельми тривіальна). Відповідний фрагмент виділений жирним
шрифтом: Option
Strict On Public
Class Delegateserver Public Delegate Sub Clientcallback(Byval Ingval As Long) Private m_clients As Clientcallback ' Використовувати конструктор за умовчанням Public Sub Registerdelegate(Byval
adelegate As Clientcallback.ByVal dolt As Boolean) ' Зазвичай тут виконується повноцінна перевірка. ' У даному прикладі функція зворотного виклику реєструється ' лише в тому випадку, якщо другий параметр рівний True. If dolt
Then m_clients =
Ctype(System.Delegate.Combine(m_ Clients.aDelegate)._ Clientcallback) End If End Sub Public Sub Callclients(Byval
Ingval As Long) m_clients( Ingval) End Sub End
Class Module
Modulel Sub Main() Dim delsrv As
New Delegateserver() delsrv.RegisterDelegate(Addressof
Delegatecallbackhandlerl.True) ' He викликається
- другий параметр рівний False! delsrv.RegisterDelegate(Addressof
Delegatecal1backhandler2.False) '
Ініціювати звернення до клієнтів delsrv.CallClients(125) Console.WriteLine("Press
enter to end.") Console.ReadLine() End Sub Public Sub Delegatecallbackhandlerkbyvalingval
As Long) System.Console.WriteLine("Delegateca11backhandlerl cal1ed") End Sub Public Sub Delegatecallbackhandler2(Byval
Ingval As Long) System.Console.Wri teline("Delegatecal1backhandler2 cal1ed") End Sub End Module
Ми
розглянули різноманітні приклади використання делегатів, проте жоден з них не мав
відношення до обробки подій. Втім, зв'язок між делегатами і подіями в
VB .NET вельми проста. При кожному використанні скороченого синтаксису обробки
подій, описаного в першій половині глави, VB .NET непомітно визначає клас
делегата для обробки події, а команда Addressof створює екземпляр делегата
для цього обробника. Наприклад, наступні два рядки еквівалентні (Eventhandler
— ім'я неявно визначуваного делегата): Addhandler Buttonl.Click.AddressOf
Me.Buttonl_Click Addhandler Buttonl.Click.New
Eventhandler(Addressof Buttonl Click) По суті,
кожна подія відповідає делегатові наступного вигляду: Public Delegate
Event (sender As Object.evt As Eventargs) Виклик Raiseevent просто
приводить до виклику Invoke для делегата, що автоматично згенерував.
|
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||