curry委托参数的最佳模式是什么(使用.NET 2.0或更高版本)?

sup*_*cat 11 .net vb.net delegates partial-application

有时,接受方法调用,使用参数完成并将其转换为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, 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
Run Code Online (Sandbox Code Playgroud)

如果我想创建一个将执行Foo(5,"Hello")的MethodInvoker,我可以创建一个

MyInvoker = NewInvoker(AddressOf Foo, 5, "Hello")
Run Code Online (Sandbox Code Playgroud)

如果我想将MyAction(X)变成Boz(X,"George",9),其中X是Double,我可以使用

MyAction = ActionOf(Of Double).Create(AddressOf Boz, "George", 9)
Run Code Online (Sandbox Code Playgroud)

一切都很漂亮,除了必须有大量的样板代码来容纳不同数量的固定和非固定参数,并且委托创建语法中没有固有的东西可以明确哪些参数是固定的,哪些是非固定的固定.有没有办法改善模式?

附录:如果从结构成员函数创建委托,机制是什么?委托似乎获得了自己的结构副本,但我不知道该副本是盒装还是取消装箱.如果它没有装箱,则用结构替换CurryAction0和CurryAction1将避免在创建委托时将CurryAction0或CurryAction1分配为单独的堆对象.但是,如果它将被装箱,那么使用结构会增加将结构复制到盒装实例而不保存任何内容的开销.

Mar*_*rkJ 1

如果你可以使用.Net 4,那么元组怎么样?

    ''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"
Run Code Online (Sandbox Code Playgroud)