Вызов функции generi c, переданной в качестве параметра в рекурсивной функции - PullRequest
2 голосов
/ 12 февраля 2020

Мое желание - запустить данную функцию по имени через AddressOf с одним входным параметром, например, Function Foo(x as Integer) As Integer. В рекурсивную функцию мне нужны два входа: имя функции _name As String и объект некоторого типа t _list As t (Integer, Double, List (Of Integer) и др. c). Цель состоит в том, чтобы обработать либо элемент, либо список элементов с именем функции, так как мне много раз приходилось обрабатывать список по заданной функции, и у меня нет sh для репликации кода обработки списка в каждом местоположении. Способы, которые я пытался назвать своими лучшими go при таком типе функции (ниже), который не обработал sh полностью, привели к этой ошибке:

Предупреждение: операция List.Test не смогли. Не удалось разрешить перегрузку, потому что Publi c 'ProcessList' не может быть вызван со следующими аргументами: 'Publi c Общая функция ProcessList (Of t) (_ fun c As Fun * c (Of Object, t), _list As System.Object) As IEnumerable (Of t) ': вывод аргумента типа завершается неудачно для параметра сопоставления аргумента' _fun c '.

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.Generi c .IList`1 [System.Int32]'.

Проблема в этой точке, вероятно, связана с метод, в котором я вызываю свою функцию ProcessList, а не саму функцию, как я думал. Я взаимодействую с GUI, который не в восторге от самостоятельного вызова ProcessList, поэтому мне нужна эта промежуточная «вспомогательная» функция, которую я, очевидно, не использую правильно.

1 Ответ

0 голосов
/ 12 февраля 2020

Вы всегда получите IEnumerable(Of T), а T может быть либо примитивом (т. Е. Integer), либо списком примитивов (т. Е. List(Of Integer)). Поэтому, когда вы пытаетесь вызвать его с помощью List, вы получите, например, List(Of List(Of Integer)).

Мы можем понять, почему, разбив ProcessList на два метода. Разница между ними заключается в типе второго аргумента: T или IEnumerable(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. Теперь оно срабатывает, когда вызывается правильная функция. Я также перестроил этот вызов, чтобы соответствовать новой сигнатуре функции.

Обе перегрузки вызываются на основе второго переданного им аргумента. Однако для каждого T вам нужен только один foo метод (либо примитив, либо его IEnumerable).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...