委托 (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 和 Lambda 表达式

每个委托类定义一个构造函数,该构造函数接收对象方法的规范。 委托构造函数的参数必须是对方法或 lambda 表达式的引用。

若要指定对方法的引用,请使用以下语法:

AddressOf [expression.]methodName

编译时类型 expression 必须是类的名称或包含指定名称的方法的接口,其签名与委托类的签名匹配。 methodName可以是共享方法或实例方法。 即使为类的默认方法创建委托,methodName 也不是可选的。

若要指定 lambda 表达式,请使用以下语法:

Function([parm As, parm2 Astype2type, ...])expression

下面的示例展示了用于为委托指定引用的 AddressOf 和 lambda 表达式。

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

函数的签名必须与委托类型的签名一致。 有关 lambda 表达式的详细信息,请参阅 Lambda 表达式。 有关委托的 lambda 表达式和 AddressOf 赋值的更多示例,请参阅宽松委托转换

标题 DESCRIPTION
如何:调用委托方法 提供一个示例,演示如何将方法与委托相关联,然后通过委托调用该方法。
如何:在 Visual Basic 中将过程传递到另一个过程 演示如何使用委托将一个过程传递给另一个过程。
宽松委托转换 介绍了如何向委托或处理程序分配 Sub 和函数,即使是在它们的签名不一致时
事件 概述 Visual Basic 中的事件。