委托 (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. 使用 AddHandler 语句时,Visual Basic 允许您通过创建委托,动态地将事件处理程序与事件相关联。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 和 Lambda 表达式AddressOf and Lambda Expressions

每个委托类均可定义将对象方法指定传递到的构造函数。Each delegate class defines a constructor that is passed the specification of an object method. 委托构造函数的自变量必须是对方法的引用或 lambda 表达式。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.

若要指定 lambda 表达式,请使用以下语法: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 和 lambda 表达式。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. 有关 lambda 表达式的详细信息,请参阅 Lambda 表达式For more information about lambda expressions, see Lambda Expressions. 有关委托的 lambda 表达式和 AddressOf 赋值的更多示例,请参阅宽松委托转换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.
如何:在 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 介绍了如何向委托或处理程序分配 Sub 和函数,即使是在它们的签名不一致时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.