有時候採用一個方法調用,使用參數完成並將其轉換爲一個MethodInvoker,它將使用這些參數調用指定的函數,而無需在當時指定參數。在其他時候,做類似的事情是有用的,但是保留一些參數。這種行爲稱爲「Currying」。在VB中做這件事最好的模式是什麼?什麼是最好的模式來委託委託參數(使用.NET 2.0或更高版本)?
可以在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, FixedType1, FixedType2)
Dim _FixedVal1 As FixedType1, _FixedVal2 As FixedType2
Sub Exec(ByVal ArgVal1 As ArgType1)
_theAction(ArgVal1, _FixedVal1, _FixedVal2)
End Sub
Sub New(ByVal theAction As Action(Of ArgType1, FixedType1, FixedType2), _
ByVal FixedVal1 As FixedType1, 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, FixedType1, FixedType2), ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) As Action(Of ArgType1)
Return AddressOf New CurriedAction1(Of ArgType1, FixedType1, FixedType2)(theSub, FixedVal1, FixedVal2).Exec
End Function
End Class
Function NewInvoker(Of FixedType1, FixedType2)(ByVal theSub As Action(Of FixedType1, FixedType2), ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) As MethodInvoker
Return AddressOf New CurriedAction0(Of FixedType1, FixedType2)(theSub, FixedVal1, FixedVal2).Exec
End Function
End Module
如果我想創建一個將執行的Foo一個MethodInvoker(5,「你好」),我可以通過創建一個
MyInvoker = NewInvoker(AddressOf Foo, 5, "Hello")
,如果我想打開MyAction(X)爲博茲(X,「喬治」,9),其中X是一個雙重的,我可以用
MyAction = ActionOf(Of Double).Create(AddressOf Boz, "George", 9)
所有非常漂亮,但它是必須有大量的樣板代碼以適應不同數量的固定參數和非固定參數,並且在委託創建語法中沒有任何固有的東西可以明確哪些參數是固定的,哪些參數是不固定的。有沒有辦法改善模式?
附錄: 如果從一個struct成員函數創建一個委託,機制是什麼?看起來委託人獲得了自己的結構副本,但我不知道該副本是裝箱還是取消裝箱。如果沒有裝箱,用結構替換CurryAction0和CurryAction1可以避免在創建代理時需要分配CurryAction0或CurryAction1作爲單獨的堆對象。但是,如果它將被裝箱,使用結構會增加複製結構到盒裝實例的開銷,而不保存任何東西。
我不確定你想要什麼,但我用藍色射擊:您可以創建委託而不指定參數,然後通過Invoke方法將它們作爲Object-Array傳遞。 – Bobby 2010-12-23 08:21:05
*'這種行爲稱爲「Currying」* - 實際上它是部分應用。 'Currying'是指某些語言的結構功能使其易於部分應用。 http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application – 2010-12-23 10:07:33
@蒂姆羅賓遜:嗯......通過這種描述,柯里裏將是創建執行部分應用程序的方法的過程,與執行行爲不同應用程序本身?無論如何,我一直在尋找一種很好的方式來做到這一點。我的方法需要大量的樣板代碼才能工作,這很煩人,但避免了關閉的麻煩。順便說一句,代表結構裝箱或拆箱?如果取消裝箱,我的模式可以通過使用結構而不是類來改善,但是如果裝箱,這將是一種浪費。 – supercat 2010-12-23 16:04:13