建立委托对象
当建立委托对象时,通常用New操作符后面紧跟委托类型的名称。使用New操作符时,必须提供一些将新委托对象绑定到目标处理方法的实现的必要信息。例子中使用QuoteOfTheDayHandler委托建立对象。
在建立委托对象前,你必须明确要把哪个处理方法绑定到该对象。处理方法既可以是共享方法也可以是实例方法,它的名称无关紧要,唯一要求是定义处理方法时它的调用特征与委托类型的相匹配。在第一个例子中,假定你写了一个叫JennysHandlers的类,它包含了一个公共方法,该方法是QuoteOfTheDayHandler委托类型的处理方法,代码如下:
Class JennysHandlers
Shared Function GetQuote(ByVal Funny As Boolean) As String
'定义处理方法的实现
End Function
End Class
如上所示,公共方法GetQuote有正确的调用特征,与QuoteOfTheDayHandler委托一起使用。当建立委托对象时,能用New操作符并传递一个含有相关信息的参数值,而那些信息允许CLR绑定一个新的对象到目标方法的实现。在Visual Basic .NET中实现它的途径是使用AddressOf操作符后面紧跟方法名。例如,你能使用下述代码建立一个绑定到GetQuote方法的委托对象:
Dim handler1 As QuoteOfTheDayHandler
handler1 = New QuoteOfTheDayHandler(AddressOf JennysHandlers.GetQuote)
需要注意的是,如果GetQuote方法的调用特征与QuoteOfTheDayHandler委托类型的不匹配, Visual Basic .NET编译器将产生一个编译错误。这些编译检查使得用委托编程比用函数指针编程的错误倾向少得多。委托的强大的类型化特性确保了通知源和它的处理方法都有相同得调用特征。
也许你记得Visual Basic早期版本中的AddressOf操作符。在Visual Basic 5.0中引入该操作符用来提供一条途径将实际函数指针传递给Win32 API中的底层函数。但是在Visual Basic .NET中AddressOf的角色已经不同了,它的主要目的是初始化委托对象。
Visual Basic .NET语言为建立委托对象提供了一种便捷的速记语法。前面的代码实例能使用下面的代码写得更简洁:
Dim handler1 As QuoteOfTheDayHandler
handler1 = AddressOf JennysHandlers.GetQuote
如上所示,为了简洁New操作符的调用能够省略。在本例中Visual Basic .NET编译器有计划地从QuoteOfTheDayHandler委托类型建立一个新对象并给该委托对象指定一个引用返回到变量handler1。你需要明白的是无论什么时候编译器期望QuoteOfTheDayHandler类型的一个委托对象,你都能简单地传递下述表达式:
AddressOf JennysHandlers.GetQuote
Visual Basic .NET编译器将表达式展开成代码,该代码建立一个新的QuoteOfTheDayHandler对象并将它绑定到处理方法GetQuote。虽然长语法看起来更明确,但是速记语法更简练并易于书写。
你已经知道怎样将一个新委托对象绑定到处理方法了,下面介绍怎样执行该委托对象绑定的处理方法。你能简单调用该委托对象的Invoke方法来运行处理方法,代码如下:
'建立并绑定委托对象
Dim handler1 As QuoteOfTheDayHandler
handler1 = AddressOf JennysHandlers.GetQuote
'执行目标方法
Dim quote As String = handler1.Invoke(True)
注意在这个例子中调用Invoke方法需要一个Boolean类型的参数并返回一个基于String类型的值。当调用委托对象的Invoke时,它通过执行目标处理方法GetQuote发送调用,调用Invoke返回的值与调用GetQuote返回的值相同。
Visual Basic .NET还提供了编写委托的另一种简洁的速记语法。你可以选择省略对委托的Invoke方法的调用。如果你不提供Invoke的显式调用,Visual Basic .NET编译器将自动为你添加该调用。看看下面的代码:
'本段代码
Dim quote1 As String = handler1.Invoke(True)
'与下面的代码功能相同
Dim quote2 As String = handler1(True)
如上所示,Invoke的调用可以是显式或隐式的。如果你用语法handler1(True)代替语法 handler1.Invoke(True),Visual Basic .NET编译器自动为你添加对Invoke的调用。因此你能简单地处理引用变量或基于委托类型的字段,就象它是实际方法的名称一样。
无论显式或隐式调用Invoke方法都是你的风格问题,在代码编译后都没有任何影响。许多程序员喜欢显式调用Invoke,因为这样使代码易于阅读;另一些宁可使用隐式调用,这样可以少点代码。
有趣的是C#编译器不允许对委托的Invoke方法显式调用。它要求程序员使用隐式风格,在该风格中委托指针被处理成象实际方法的名称一样。
