Иллюстрированный самоучитель по 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

На самом деле использовать Invoke необязательно — достаточно передать делегату нужные параметры. VB .NET поймет команду aDelegate(" Hello"), которая выглядит значительно проще.



В этом нетрудно убедиться, просматривая полученный 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.


Содержание раздела