パラメーターを備えたメソッド呼び出しを取得し、その時点でパラメーターを指定しなくても、それらのパラメーターで指定された関数を呼び出す MethodInvoker に変換すると便利な場合があります。他の場合には、同様のことを行うと便利ですが、いくつかのパラメーターは開いたままにします。このタイプのアクションは「カリー化」と呼ばれます。VBでこれを行うための最良のパターンは何ですか?
VB 2010 でラムダ式を使用することは可能ですが、ラムダ式はエディット コンティニュと互換性がなく、ラムダ式が作成するクロージャーは参照による予期しない動作をする可能性があります。別のアプローチは、次に示すようないくつかの一般的なメソッドを定義することです。
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(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)
さまざまな数の固定および非固定パラメーターに対応するために膨大な量の定型コードが必要であり、どのパラメーターが固定され、どのパラメーターが固定されていないかを明確にするデリゲート作成構文に固有のものがないことを除いて、すべて非常に巧妙です。修繕。パターンを改善する方法はありますか?
補遺:デリゲートが構造体メンバー関数から作成された場合のメカニズムは何ですか? デリゲートは構造体の独自のコピーを取得しているようですが、そのコピーがボックス化されているかボックス化されていないかはわかりません。ボックス化されていない場合、CurryAction0 と CurryAction1 を構造体に置き換えると、デリゲートの作成時に CurryAction0 または CurryAction1 を別のヒープ オブジェクトとして割り当てる必要がなくなります。ただし、ボックス化する場合、構造体を使用すると、何も保存せずに構造体をボックス化されたインスタンスにコピーするというオーバーヘッドが追加されます。