2

AddressOf私の望みは、特定の関数を 1 つの入力パラメーターを使用して名前で実行することFunction Foo(x as Integer) As Integerです。再帰関数に必要な 2 つの入力は、関数名と、何らかの型 t (Integer、Double、List(Of Integer) など)_name As Stringのオブジェクトです。_list As t目標は、関数名を使用して要素または要素のリストを処理することです。これは、特定の関数でリストを処理する必要が何度もあり、各場所でリスト処理コードを複製したくないためです。完全にクラッシュしなかったこのタイプの関数(以下)で最善を尽くそうとした方法は、このエラーを引き起こしました:

警告: List.Test 操作に失敗しました。次の引数でパブリック 'ProcessList' を呼び出すことができないため、オーバーロードの解決に失敗しました: 'Public Shared Function ProcessList(Of t)(_func As Func(Of Object,t), _list As System.Object) As IEnumerable(Of t)':型引数の推論は、引数一致パラメーター '_func' で失敗します。

Iterator Function ProcessList(Of t)(_func As Func(Of Object, t), _list As Object) As IEnumerable(Of t)
    If _list.GetType = GetType(List(Of t)) Then
        Yield _list.SelectMany(Function(l) ProcessList(_func, l))
    Else
        Yield _func(_list)
    End If
End Function

参考までに、必要なことを効果的に実行する Python コードのスニペットを見つけましたが、この方向 (Python から VB.net) への変換には少し慣れていません。 VB.net。Python スニペットは次のとおりです。

def ProcessList(_func, _list):
    return map(lambda x: ProcessList(_func, x) if type(x)==list else _func(x), _list)

この関数を呼び出す方法、または私のアプローチに欠陥がある場合にこの関数を作り直す方法についての助けをいただければ幸いです。

アップデート:

メソッドが機能しているという@djvの情報に基づいて、関数の呼び出し方法と他のいくつかのことを再検討しました。まず、これらの関数とのインターフェイス方法の性質上、上記の関数を次のように公開する必要があります。

Public Shared Function Foo(ByVal _input As Object) As Object
    Return Utilities.ProcessList(AddressOf Bar, _input)
End Function

また、次のエラー メッセージが表示されるようになりました。

警告: List.Test 操作に失敗しました。タイプ 'System.Int32' のオブジェクトをタイプ 'System.Collections.Generic.IList`1[System.Int32]' にキャストできません。

この時点での問題は、私が思っていた関数自体ではなく、おそらく ProcessList 関数を呼び出すメソッドにあります。ProcessList を単独で呼び出すことに満足していない GUI とやり取りしているため、この中間の「ヘルパー」関数が必要ですが、これは明らかに正しく使用されていません。

4

1 に答える 1

0

常に取得され、プリミティブ (つまり) またはプリミティブのリスト(つまり ) のいずれかにIEnumerable(Of T)なります。そのため、List を使用して呼び出そうとすると、たとえばが得られます。TIntegerList(Of Integer)List(Of List(Of Integer))

ProcessListその理由は、 2 つの方法に分割することでわかります。それらの違いは、次のいずれかである 2 番目の引数の型ですTIEnumerable(Of T)

Sub Main()
    Dim i As Integer = 1
    Dim li As New List(Of Integer) From {1, 1, 1}
    Dim ri As IEnumerable(Of Integer) = ProcessList(AddressOf foo, i).ToList()
    Dim rli As IEnumerable(Of Integer) = ProcessList(AddressOf foo, li).ToList()

    Dim d As Double = 1.0#
    Dim ld As New List(Of Double) From {1.0#, 1.0#, 1.0#}
    Dim rd As IEnumerable(Of Double) = ProcessList(AddressOf foo, d).ToList()
    Dim rld As IEnumerable(Of Double) = ProcessList(AddressOf foo, ld).ToList()

    Console.ReadLine()
End Sub

Function ProcessList(Of T)(f As Func(Of T, T), p As IEnumerable(Of T)) As IEnumerable(Of T)
    Return p.Select(Function(i) ProcessList(f, i)).SelectMany(Function(i) i)
End Function

Iterator Function ProcessList(Of T)(f As Func(Of T, T), p As T) As IEnumerable(Of T)
    Yield f(p)
End Function

Function foo(param As Integer) As Integer
    Return param + 1
End Function

Function foo(param As Double) As Double
    Return param + 1.0#
End Function

以前は、SelectMany を実行した元のコードの行にヒットすることさえできませんでした。これで、適切な関数が呼び出されたときにヒットします。また、新しい関数シグネチャに合わせてその呼び出しを再調整しました。

オーバーロードは、渡された 2 番目の引数に基づいて両方とも呼び出されます。fooただし、 T (プリミティブまたはその IEnumerable) ごとに必要なメソッドは 1 つだけです。

于 2020-02-12T19:41:19.053 に答える