有时,采用方法调用,使用参数完成,并将其转换成MethodInvoker,该函数将使用这些参数调用指定的函数,而无需在当时指定参数.在其他时候,做一些类似的事情是有用的,但是留下一些参数.这种动作叫做“Currying”.在VB中最好的做法是什么?
可以在VB 2010中使用lambda表达式,但lambda表达式与edit-and-continue不兼容,并且它们创建的闭包可以具有意外的副参考行为.另一种方法是定义一些通用方法,如下所示:
Public Module CurryMagic Delegate Sub Action(Of T1,T2)(ByVal P1 As T1,ByVal P2 As T2) Delegate Sub Action(Of T1,T2,T3)(ByVal P1 As T1,ByVal P2 As T2,ByVal P3 As T3) Class CurriedAction0(Of FixedType1,FixedType2) Dim _theAction As Action(Of FixedType1,FixedType2) Dim _FixedVal1 As FixedType1,_FixedVal2 As FixedType2 Sub Exec() _theAction(_FixedVal1,_FixedVal2) End Sub Sub New(ByVal theAction As Action(Of FixedType1,FixedType2),_ ByVal FixedVal1 As FixedType1,ByVal FixedVal2 As FixedType2) _theAction = theAction _FixedVal1 = FixedVal1 _FixedVal2 = FixedVal2 End Sub End Class Class CurriedAction1(Of ArgType1,FixedType1,FixedType2) Dim _theAction As Action(Of ArgType1,_FixedVal2 As FixedType2 Sub Exec(ByVal ArgVal1 As ArgType1) _theAction(ArgVal1,_FixedVal1,_FixedVal2) End Sub Sub New(ByVal theAction As Action(Of ArgType1,ByVal FixedVal2 As FixedType2) _theAction = theAction _FixedVal1 = FixedVal1 _FixedVal2 = FixedVal2 End Sub End Class Class ActionOf(Of ArgType1) Shared Function Create(Of FixedType1,FixedType2)(ByVal theSub As Action(Of ArgType1,ByVal FixedVal1 As FixedType1,ByVal FixedVal2 As FixedType2) As Action(Of ArgType1) Return AddressOf New CurriedAction1(Of ArgType1,FixedType2)(theSub,FixedVal1,FixedVal2).Exec End Function End Class Function NewInvoker(Of FixedType1,FixedType2)(ByVal theSub As Action(Of FixedType1,ByVal FixedVal2 As FixedType2) As MethodInvoker Return AddressOf New CurriedAction0(Of FixedType1,FixedVal2).Exec End Function End Module
如果我想创建一个将执行Foo(5,“Hello”)的MethodInvoker,我可以创建一个使用
MyInvoker = NewInvoker(AddressOf Foo,5,"Hello")
如果我想将MyAction(X)转换成Boz(X,“George”,9),其中X是Double,我可以使用
MyAction = ActionOf(Of Double).Create(AddressOf Boz,"George",9)
除了必须有大量的样板代码以适应不同数量的固定和非固定参数之外,所有这些都很漂亮,而委托创建语法中没有什么固有的,这清楚了哪些参数是固定的,固定.有没有办法改善模式?
附录:
如果委托是从一个struct成员函数创建的,那么机制是什么?看来,委托获取自己的结构体副本,但是我不知道该副本是否装箱或取消装箱.如果没有装箱,则用结构体替换CurryAction0和CurryAction1将避免在创建委托时将CurryAction0或CurryAction1分配为单独的堆对象.如果将要装箱,那么使用一个结构体会增加将结构复制到盒装实例的开销,而不保存任何东西.
如果可以使用.Net 4,怎么样
tuples?
''Create new tuple instance with two items. Dim tuple As Tuple(Of Integer,String) = _ New Tuple(Of Integer,String)(5,"Hello") ''Now you only have one argument to curry,packaging both parameters ''Access the parameters like this (strongly typed) Debug.Print tuple.Item1 '' 5 Debug.Print tuple.Item2 '' "Hello"