Делегаты (Visual Basic)
Делегаты являются объектами, которые ссылаются на методы. Иногда их описывают как типобезопасные указатели функций, поскольку они похожи на указатели функций, используемые в других языках программирования. Но в отличие от указателей функций, Visual Basic делегаты являются ссылочным типом на основе классаSystem.Delegate. Делегаты могут ссылаться на оба вида общих методов — на методы, которые могут вызываться без определенного экземпляра класса, и на методы экземпляра.
Делегаты и события
Делегаты полезны в тех ситуациях, когда требуется промежуточное звено между вызывающей и вызываемой процедурами. Например, вы хотите создать объект, который создает события и в зависимости от обстоятельств может вызывать разные обработчики событий. К сожалению, этот объект не может знать заранее, какой обработчик событий обрабатывает конкретное событие. Visual Basic позволяет динамически связывать обработчики событий с событиями, создавая делегат при использовании инструкцииAddHandler
. Во время выполнения делегат передает вызовы в соответствующий обработчик событий.
Хотя вы можете создавать собственные делегаты, в большинстве случаев Visual Basic создает делегат и заботится о них. Например, инструкция Event
неявно определяет класс делегата с именем <EventName>EventHandler
. Он размещается как вложенный класс в том классе, который содержит инструкцию Event
, а его сигнатура совпадает с сигнатурой события. Инструкция AddressOf
неявно создает экземпляр делегата, который ссылается на конкретную процедуру. Следующие два фрагмента кода эквивалентны. В первой строке вы видите явное создание экземпляра EventHandler
, который ссылается на метод Button1_Click
, переданный в качестве аргумента. Вторая строка делает то же самое, но более удобна в использовании.
AddHandler Button1.Click, New EventHandler(AddressOf Button1_Click)
' The following line of code is shorthand for the previous line.
AddHandler Button1.Click, AddressOf Me.Button1_Click
Сокращенный способ создания делегатов вы можете использовать в любом месте кода, где компилятор может определить тип делегата по контексту.
Объявление событий, использующих существующий тип делегата
В некоторых ситуациях вам потребуется объявить, чтобы событие использовало в качестве своего делегата уже существующий тип делегата. Для этого используется следующий синтаксис:
Delegate Sub DelegateType()
Event AnEvent As DelegateType
Это удобно, когда нужно направить к одному обработчику несколько событий.
Переменные и параметры делегата
Делегаты можно использовать для других, не связанных с событиями задач, например в свободной потоковой модели или в процедурах, которые должны вызывать разные версии функции во время выполнения.
Предположим, у вас есть рекламное приложения, которое содержит список с названиями автомобилей. Рекламные объявления сортируются по названию, которое обычно содержит модель автомобиля. Если у некоторых автомобилей перед моделью указан год производства, возникает проблема. Эта проблема связана с тем, что встроенная функция сортировки упорядочивает значения только по кодам знаков. В результате все объявления, которые начинаются с даты, располагаются первыми, и лишь затем идут объявления с моделью в начале строки.
Чтобы устранить эту проблему, можно создать в классе специальную процедуру сортировки, которая для большинства списков использует стандартную сортировку по алфавиту, но во время выполнения переключается на пользовательскую сортировку для объявлений о продаже автомобилей. Для этого во время выполнения пользовательская процедура сортировки передается классу сортировки с помощью делегатов.
AddressOf и лямбда-выражения
Каждый класс делегата определяет конструктор, которому передается спецификация метода объекта. Аргумент конструктора делегата должен быть ссылкой на метод или лямбда-выражение.
Чтобы указать ссылку на метод, используйте следующий синтаксис:
AddressOf
[expression
.]methodName
Тип expression
во время компиляции должен представлять собой имя класса или интерфейса, который содержит метод с указанным именем, сигнатура которого соответствует сигнатуре класса делегата. methodName
должен быть общим методом или методом экземпляра. methodName
всегда является обязательным, даже если делегат создается для метода по умолчанию в классе.
Чтобы указать лямбда-выражение, используйте следующий синтаксис:
Function
([parm
As type
, parm2
As type2
, ...]) expression
В следующем примере показано, как использовать AddressOf
и лямбда-выражения для указания ссылки на делегат.
Module Module1
Sub Main()
' Create an instance of InOrderClass and assign values to the properties.
' InOrderClass method ShowInOrder displays the numbers in ascending
' or descending order, depending on the comparison method you specify.
Dim inOrder As New InOrderClass
inOrder.Num1 = 5
inOrder.Num2 = 4
' Use AddressOf to send a reference to the comparison function you want
' to use.
inOrder.ShowInOrder(AddressOf GreaterThan)
inOrder.ShowInOrder(AddressOf LessThan)
' Use lambda expressions to do the same thing.
inOrder.ShowInOrder(Function(m, n) m > n)
inOrder.ShowInOrder(Function(m, n) m < n)
End Sub
Function GreaterThan(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
Return num1 > num2
End Function
Function LessThan(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
Return num1 < num2
End Function
Class InOrderClass
' Define the delegate function for the comparisons.
Delegate Function CompareNumbers(ByVal num1 As Integer, ByVal num2 As Integer) As Boolean
' Display properties in ascending or descending order.
Sub ShowInOrder(ByVal compare As CompareNumbers)
If compare(_num1, _num2) Then
Console.WriteLine(_num1 & " " & _num2)
Else
Console.WriteLine(_num2 & " " & _num1)
End If
End Sub
Private _num1 As Integer
Property Num1() As Integer
Get
Return _num1
End Get
Set(ByVal value As Integer)
_num1 = value
End Set
End Property
Private _num2 As Integer
Property Num2() As Integer
Get
Return _num2
End Get
Set(ByVal value As Integer)
_num2 = value
End Set
End Property
End Class
End Module
Сигнатура функции должна соответствовать сигнатуре типа делегата. Дополнительные сведения о лямбда-выражениях см. в разделе "Лямбда-выражения". Дополнительные примеры лямбда-выражений и назначений AddressOf
делегатам см. в статье Relaxed Delegate Conversion (Неявное преобразование делегата).
См. также
Заголовок | Описание |
---|---|
Практическое руководство. Вызов метода делегата | Предоставляет пример, в котором показано, как связать метод с делегатом и вызвать этот метод через делегат. |
Практическое руководство. Передача процедур другой процедуре в Visual Basic | Демонстрирует использование делегатов для передачи одной процедуры в другую процедуру. |
Неявное преобразование делегата | Описывает, как можно назначить делегаты или обработчики для подпрограмм и функций, если их сигнатуры не совпадают |
События | Предоставляет обзор событий в Visual Basic. |