Делегаты (Visual Basic)

Делегаты — это объекты, которые ссылаются на методы.Иногда их описывают как type-safe function pointers, поскольку они аналогичны указателям на функции, используемым в других языках программирования.Но в отличие от указателей на функции, делегаты 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

Сигнатура функции должна соответствовать типу делегата.Дополнительные сведения о лямбда-выражениях см. в разделе Лямбда-выражения (Visual Basic).Дополнительные примеры назначения делегатам лямбда-выражений и AddressOf см. в разделе Неявное преобразование делегата (Visual Basic).

Связанные разделы

Заголовок

Описание

Практическое руководство. Вызов метода делегата (Visual Basic)

Содержит пример, в котором показано, как связать метод с делегатом, а затем вызвать метод через делегат.

Практическое руководство. Передача процедур другой процедуре в Visual Basic

Демонстрирует использование делегатов для передачи одной процедуры в другую.

Неявное преобразование делегата (Visual Basic)

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

События (Visual Basic)

Содержит общие сведения о событиях в Visual Basic.