Поделиться через


Делегаты (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 как type, parm2 как 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 назначений делегата см. в разделе "Расслабленное преобразование делегатов".

Название Описание
Как вызвать метод делегата В этом примере показано, как связать метод с делегатом, а затем вызвать этот метод с помощью делегата.
Практическое руководство. Передача процедур в другую процедуру в Visual Basic Демонстрирует использование делегатов для передачи одной процедуры в другую процедуру.
Упрощенное преобразование делегатов Описание того, как можно назначать дочерние элементы и функции делегатам или обработчикам, даже если их подписи не идентичны
События Общие сведения о событиях в Visual Basic.