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

Делегаты являются объектами, которые ссылаются на методы.Delegates are objects that refer to methods. Иногда их описывают как типобезопасные указатели функций, поскольку они похожи на указатели функций, используемые в других языках программирования.They are sometimes described as type-safe function pointers because they are similar to function pointers used in other programming languages. Но в отличие от указателей на функции, Visual Basic делегаты являются ссылочным типом, основанным на System.Delegateкласса.But unlike function pointers, Visual Basic delegates are a reference type based on the class System.Delegate. Делегаты могут ссылаться на оба вида общих методов — на методы, которые могут вызываться без определенного экземпляра класса, и на методы экземпляра.Delegates can reference both shared methods — methods that can be called without a specific instance of a class — and instance methods.

Делегаты и событияDelegates and Events

Делегаты полезны в тех ситуациях, когда требуется промежуточное звено между вызывающей и вызываемой процедурами.Delegates are useful in situations where you need an intermediary between a calling procedure and the procedure being called. Например, вы хотите создать объект, который создает события и в зависимости от обстоятельств может вызывать разные обработчики событий.For example, you might want an object that raises events to be able to call different event handlers under different circumstances. К сожалению, этот объект не может знать заранее, какой обработчик событий обрабатывает конкретное событие.Unfortunately, the object raising the events cannot know ahead of time which event handler is handling a specific event. Visual Basic позволяет динамически связывать обработчики событий с событиями, создавая делегат при использовании инструкции AddHandler.Visual Basic lets you dynamically associate event handlers with events by creating a delegate for you when you use the AddHandler statement. Во время выполнения делегат передает вызовы в соответствующий обработчик событий.At run time, the delegate forwards calls to the appropriate event handler.

Несмотря на то, что вы можете создавать собственные делегаты, в большинстве случаев Visual Basic создает делегат и следит за информацией.Although you can create your own delegates, in most cases Visual Basic creates the delegate and takes care of the details for you. Например, инструкция Event неявно определяет класс делегата с именем <EventName>EventHandler. Он размещается как вложенный класс в том классе, который содержит инструкцию Event, а его сигнатура совпадает с сигнатурой события.For example, an Event statement implicitly defines a delegate class named <EventName>EventHandler as a nested class of the class containing the Event statement, and with the same signature as the event. Инструкция AddressOf неявно создает экземпляр делегата, который ссылается на конкретную процедуру.The AddressOf statement implicitly creates an instance of a delegate that refers to a specific procedure. Следующие два фрагмента кода эквивалентны.The following two lines of code are equivalent. В первой строке вы видите явное создание экземпляра EventHandler, который ссылается на метод Button1_Click, переданный в качестве аргумента.In the first line, you see the explicit creation of an instance of EventHandler, with a reference to method Button1_Click sent as the argument. Вторая строка делает то же самое, но более удобна в использовании.The second line is a more convenient way to do the same thing.

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

Сокращенный способ создания делегатов вы можете использовать в любом месте кода, где компилятор может определить тип делегата по контексту.You can use the shorthand way of creating delegates anywhere the compiler can determine the delegate's type by the context.

Объявление событий, использующих существующий тип делегатаDeclaring Events that Use an Existing Delegate Type

В некоторых ситуациях вам потребуется объявить, чтобы событие использовало в качестве своего делегата уже существующий тип делегата.In some situations, you may want to declare an event to use an existing delegate type as its underlying delegate. Для этого используется следующий синтаксис:The following syntax demonstrates how:

Delegate Sub DelegateType()
Event AnEvent As DelegateType

Это удобно, когда нужно направить к одному обработчику несколько событий.This is useful when you want to route multiple events to the same handler.

Переменные и параметры делегатаDelegate Variables and Parameters

Делегаты можно использовать для других, не связанных с событиями задач, например в свободной потоковой модели или в процедурах, которые должны вызывать разные версии функции во время выполнения.You can use delegates for other, non-event related tasks, such as free threading or with procedures that need to call different versions of functions at run time.

Предположим, у вас есть рекламное приложения, которое содержит список с названиями автомобилей.For example, suppose you have a classified-ad application that includes a list box with the names of cars. Рекламные объявления сортируются по названию, которое обычно содержит модель автомобиля.The ads are sorted by title, which is normally the make of the car. Если у некоторых автомобилей перед моделью указан год производства, возникает проблема.A problem you may face occurs when some cars include the year of the car before the make. Эта проблема связана с тем, что встроенная функция сортировки упорядочивает значения только по кодам знаков. В результате все объявления, которые начинаются с даты, располагаются первыми, и лишь затем идут объявления с моделью в начале строки.The problem is that the built-in sort functionality of the list box sorts only by character codes; it places all the ads starting with dates first, followed by the ads starting with the make.

Чтобы устранить эту проблему, можно создать в классе специальную процедуру сортировки, которая для большинства списков использует стандартную сортировку по алфавиту, но во время выполнения переключается на пользовательскую сортировку для объявлений о продаже автомобилей.To fix this, you can create a sort procedure in a class that uses the standard alphabetic sort on most list boxes, but is able to switch at run time to the custom sort procedure for car ads. Для этого во время выполнения пользовательская процедура сортировки передается классу сортировки с помощью делегатов.To do this, you pass the custom sort procedure to the sort class at run time, using delegates.

AddressOf и лямбда-выраженияAddressOf and Lambda Expressions

Каждый класс делегата определяет конструктор, которому передается спецификация метода объекта.Each delegate class defines a constructor that is passed the specification of an object method. Аргумент конструктора делегата должен быть ссылкой на метод или лямбда-выражение.An argument to a delegate constructor must be a reference to a method, or a lambda expression.

Чтобы указать ссылку на метод, используйте следующий синтаксис:To specify a reference to a method, use the following syntax:

AddressOf [expression.]methodNameAddressOf [expression.]methodName

Тип expression во время компиляции должен представлять собой имя класса или интерфейса, который содержит метод с указанным именем, сигнатура которого соответствует сигнатуре класса делегата.The compile-time type of the expression must be the name of a class or an interface that contains a method of the specified name whose signature matches the signature of the delegate class. methodName должен быть общим методом или методом экземпляра.The methodName can be either a shared method or an instance method. methodName всегда является обязательным, даже если делегат создается для метода по умолчанию в классе.The methodName is not optional, even if you create a delegate for the default method of the class.

Чтобы указать лямбда-выражение, используйте следующий синтаксис:To specify a lambda expression, use the following syntax:

Function ([parm As type, parm2 As type2, ...]) expressionFunction ([parm As type, parm2 As type2, ...]) expression

В следующем примере показано, как использовать AddressOf и лямбда-выражения для указания ссылки на делегат.The following example shows both AddressOf and lambda expressions used to specify the reference for a delegate.

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

Сигнатура функции должна соответствовать сигнатуре типа делегата.The signature of the function must match that of the delegate type. Дополнительные сведения о лямбда-выражениях см. в разделе Лямбда-выражения.For more information about lambda expressions, see Lambda Expressions. Дополнительные примеры лямбда-выражений и назначений AddressOf делегатам см. в статье Relaxed Delegate Conversion (Неявное преобразование делегата).For more examples of lambda expression and AddressOf assignments to delegates, see Relaxed Delegate Conversion.

НазваниеTitle ОписаниеDescription
Практическое руководство. Вызов метода делегатаHow to: Invoke a Delegate Method Предоставляет пример, в котором показано, как связать метод с делегатом и вызвать этот метод через делегат.Provides an example that shows how to associate a method with a delegate and then invoke that method through the delegate.
How to: Pass Procedures to Another Procedure in Visual Basic (Практическое руководство. Передача процедур другой процедуре в Visual Basic)How to: Pass Procedures to Another Procedure in Visual Basic Демонстрирует использование делегатов для передачи одной процедуры в другую процедуру.Demonstrates how to use delegates to pass one procedure to another procedure.
Неявное преобразование делегатаRelaxed Delegate Conversion Описывает, как можно назначить делегаты или обработчики для подпрограмм и функций, если их сигнатуры не совпадаютDescribes how you can assign subs and functions to delegates or handlers even when their signatures are not identical
СобытияEvents Предоставляет обзор событий в Visual Basic.Provides an overview of events in Visual Basic.