假定您在为一家新计算机公司起草业务计划面对如何处理产品分发的问题当然您从未考虑过亲自将每一件新产品交付到每位客户的手中相反您会将此责任委托给像 FedEx 或 UPS 等配送服务机构您必须事先做三个决定该行动是什么(交付产品)参数是什么(客户地址)以及返回值是什么(付款)然后当实际有一个包裹要交付时您就可以将责任委托给某个特定的配送服务机构
在 Microsoft NET 编程中您会面对需要执行某种特定操作但是无法预先知道将调用何种方法来执行该操作的情况例如在单击某个按钮时可能需要调用某个方法但是在设计该按钮时却无法知道将调用哪个方法您需要有一种方法来描述要调用何种方法这正是委托派上用场的地方在本文中我将探索如何在 Visual Basic NET 中使用委托
入门
委托是一种引用类型表示带有特定签名和返回类型的方法可以在该委托中封装任何匹配的方法另外还可以将委托看作是对方法的引用
要了解其工作方式我们来看一个委托解决的问题正如您将在图 中看到的我将创建一个 Pair 类的简单集合其中有两个对象Pair 类创建一个名为 thePair 的私有数组其中包括两个成员
Public Class Pair
Private thePair() As Object
构造函数接受两个对象然后按接收顺序将其添加到此内部数组中
Public Sub New(ByVal firstObject As Object ByVal secondObject As Object)
thePair() = firstObject
thePair() = secondObject
End Sub
Pair 提供其它三种方法SortReverseSort 以及 ToString 的重写Sort 方法将对内部数组中的两个对象进行排序当然您不希望让 Pair 类知道对这两个对象进行排序的测试因为实际上您可能在 Pair 中存储任何类型的对象(StudentsDogsEmployeesButtons等等)Pair 如何才能知道如何对所有这些不同类型的对象进行排序呢?
解决方案是将责任(确定哪个对象最小)委托给对象自己Pair 如何实现这一点?使用委托(参见图 )
在 Pair 类中我已经定义了一个委托以封装(引用)比较两个对象的方法然后确定哪个较小(不管较小是如何定义的确定的比较类都是合适的)
Public Delegate Function WhichIsSmaller( _
ByVal obj As Object ByVal obj As Object) As Comparison
这是一个相当复杂的定义让我们来一段一段地查看这个定义
; Public 关键字将该委托声明为 Pair 类的一个公共成员
; Delegate 关键字表示您正在创建一个委托(而不是一个方法或属性)
; Function 关键字表示该委托将用于封装一个函数(而不是一个子程序)
; WhichIsSmaller 标识符是该委托的名称
; 括号内的值是该委托将封装的方法的签名即该委托可能封装任何接受两个对象作为参数的函数
; 最后的关键字 As Comparison 是该委托可能封装的方法的返回类型Comparison 是一个在 Pair 类中定义的枚举
Public Enum Comparison
theFirst =
theSecond =
End Enum
用该委托封装的方法必须返回 ComparisontheFirst 或 ComparisontheSecond
总之刚刚展示的语句在名为 WhichIsSmaller 的 Pair 类中定义了一个公共委托它封装接受两个对象作为参数的函数并返回 Comparison 枚举类型的一个实例
可以在该委托的实例中封装任何匹配的方法例如您的 Pair 集合可能包含两个 Student 对象如下所示
Public Class Student
Private name As String
Public Sub New(ByVal name As String)
Mename = name
End Sub
other Student methods here
End Class
您的 Student 类必须创建一个与 WhichIsSmaller 委托相匹配的方法例如您可以创建一个 WhichStudentIsSmaller 方法(参见图 中的代码)该方法匹配所要求的签名它接受两个对象作为参数并且返回一个 Comparison 值
因为我的 WhichStudentIsSmaller 方法需要将这些参数用作 Student 对象而不是作为更一般的 Object 类型我将把这些参数强制转换为 Student这是类型安全的因为我决不会用其他任何类型的参数来调用该方法
一旦我强制转换了这两个对象我就可以对它们进行比较在本例中我将按字母顺序比较它们的名称值并返回合适的枚举值PairComparisontheFirst 或 PairComparisontheSecond
按字母顺序的比较是通过调用 String 类的共享方法 Compare 来完成的如果按照字母表第一个字符串排在第二个前面(sname 的字母顺序在 sname 之前)则 Compare 返回一个负整数值如果按照字母表第二个字符串排在第一个前面则 Compare 返回一个正整数值如果相同则返回零
其他类也能创建与 WhichIsSmaller 委托相匹配的方法例如我还可以创建 Dog 类
Public Class Dog
Private weight As Integer
Public Sub New(ByVal weight As Integer)
Meweight = weight
End Sub
other Dog methods here
End Class
该 Dog 类将实现一个方法基于重量对两个 Dog 实例进行比较
Public Shared Function WhichDogIsSmaller( _
ByVal o As Object ByVal o As Object) As parison
Dim d As Dog = DirectCast(o Dog)
Dim d As Dog = DirectCast(o Dog)
If dweight > dweight Then
Return PairComparisontheSecond
Else
Return PairComparisontheFirst
End If
End Function
现在该 Pair 类就可以创建其 Sort 方法了它将接受一个 WhichIsSmaller 委托作为参数
Public Sub Sort(ByVal theDelegatedFunc As WhichIsSmaller)
If theDelegatedFunc(thePair() thePair()) = _
ComparisontheSecond Then
Dim temp As Object = thePair()
thePair() = thePair()
thePair() = temp
End If
End Sub
Sort 方法通过委托来调用委托的方法传递 Pair 数组的两个成员返回一个枚举值如果该值为 ComparisontheSecond就知道第二个对象比第一个类型小Sort 方法甚至无需知道这两个对象的类型就可以知道这一点!然后它可以将这两个对象颠倒过来如果委托的方法返回 ComparisontheFirst则无需交换
实例化委托
要对此进行测试可以创建两个 Student 对象如下所示
Dim Jesse As New Student(Jesse)
Dim Stacey As New Student(Stacey)
然后将其添加到一个新的 Pair 对象中 Dim studentPair As New Pair(Jesse Stacey)随后可以实例化一个 WhichIsSmaller 委托传递知道如何比较这两个 Student 对象的 Student 的匹配方法
Dim theStudentDelegate As New _
PairWhichIsSmaller(AddressOf StudentWhichStudentIsSmaller)
现在我可以将这个委托传递给 Sort 方法以便对这个两个学生进行排序
studentPairSort(theStudentDelegate)
类似地我可以创建两个 Dog 对象将其添加到 Pair并基于比较两个 Dog 的 Dog 方法实例化一个委托然后将该委托传递给 Dog 对的排序方法如以下各行所示
make two dogs
Dim Milo As New Dog()
Dim Fred As New Dog()
store the two dogs in a Pair
Dim dogPair As New Pair(Milo Fred)
instantiate a delegate
Dim theDogDelegate As New _
PairWhichIsSmaller(AddressOf DogWhichDogIsSmaller)
invoke Sort pass in the delegate
dogPairSort(theDogDelegate)
Pair 类有一个接受相同的委托作为 Sort 的 ReverseSort我同样可以将您刚刚创建的 Student 和 Dog 委托传递给 ReverseSort
studentPairReverseSort(theStudentDelegate)dogPairReverseSort(theDogDelegate)
您可能已经猜到了ReverseSort 的逻辑与 Sort 的逻辑相反即仅在比较方法返回的值指示第一个对象比第二个对象小的情况下才交换 Pair 中的这两项
实例方法与委托
在图 所示示例中封装了 Dog 和 Student 类的共享方法相反可以同样容易地将封装的方法声明为实例方法(即非共享方法)
Public Comparison
WhichStudentIsSmaller(o as Object o as Object)
尽管可以将该方法封装在委托中但是必须通过实例而不是通过类来引用它如下所示
Dim theStudentDelegate As _
New PairWhichIsSmaller(AddressOf JesseWhichStudentIsSmaller)
尽管重复调用一个封装了实例方法的委托比调用一个静态方法效率更高您还是需要一个实例来调用该方法
共享委托
中声明委托的方法的一个缺点是调用类 (Tester) 必须实例化所需