Вызов функции F # из функции передачи С# в качестве параметра

У меня есть следующая функция F #

let Fetch logger id = 
    logger "string1" "string2"
    // search a database with the id and return a result

В моем классе С# я хочу вызвать функцию Fetch F #, издевающуюся над функцией журнала. Таким образом, у меня есть следующая функция С# как mocker.

void Print(string x, string y) { // do nothing }

Я пытаюсь вызвать функцию F # из класса С# со следующим.

var _logger = FuncConvert.ToFSharpFunc<string, string>(Print);
var _result = Fetch(logger, 3);

Проблема с FuncConvert.ToFSharpFunc заключается в том, что он принимает только один аргумент типа. Когда я меняю функцию Fetch F # logger на следующую, он отлично работает, когда я использую ToFSharpFunc (Print), где функция С# Print также принимает одну строку.

let Fetch logger id = 
    logger "string1"
    // search a database with the id and return a result

Кто-нибудь получил идеи?

Ответ 1

Укороченная версия

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);

MyOtheProject.MyModule.Fetch(logger, 3);

Длинная версия

Функции F # принимают только один аргумент. Несколько аргументов по существу создают вложенные функции. Вам нужно сделать то же самое на стороне С#.

Проверьте тип параметра logger в С# с Intellisense. Это

Microsoft.FSharp.Core.FSharpFunc<string, Microsoft.FSharp.Core.FSharpFunc<string, a>>

FuncConvert.ToFSharpFunc не может создать это. FuncFromTupled, хотя может создать это из FSharpFunc, который берет Tuple с несколькими полями в качестве аргумента.

Это то, что может быть создано ToFsharpFunc:

FSharpFunc<Tuple<string,string>,Unit> tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(
       t=> Print(t.Item1,t.Item2));

или же

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=> Print(t.Item1,t.Item2));

Как FuncFromTupled описании FuncFromTupled, это A utility function to convert function values from tupled to curried form. , tupleLogger - это форма, которую мы должны преобразовать в карри.

var logger = FuncConvert.FuncFromTupled(tupleLogger);

Полученный код выглядит так:

var tupleLogger = FuncConvert.ToFSharpFunc<Tuple<string,string>>(t=>Print(t.Item1,t.Item2));
var logger = FuncConvert.FuncFromTupled(tupleLogger);

MyOtheProject.MyModule.Fetch(logger, 3);

Вы можете создать функцию утилиты для объединения двух преобразований:

public static class MyFuncConvert
{
    public static FSharpFunc<T1, FSharpFunc<T2, Unit>> ToFSharpFunc<T1, T2>(Action<T1, T2> action)
    {
        var tupled = FuncConvert.ToFSharpFunc<Tuple<T1, T2>>(
                                  t => action(t.Item1, t.Item2));
        var curried = FuncConvert.FuncFromTupled(tupled);
        return curried;
    }
}

Что позволит вам написать:

var logger = MyFuncConvert.ToFSharpFunc<string,string>(Print);

Ответ 2

Функции F # могут иметь только один аргумент. Когда у вас есть, например: logger "string1" "string2" выражение logger "string1" создает в нем еще одну функцию с "string1" которая затем может принимать "string2" в качестве аргумента. Итак, чтобы преобразовать это, вы можете создать такой вспомогательный метод:

public static class FuncConvertExt
{
    public static FSharpFunc<T1, FSharpFunc<T2, Unit>> Create<T1, T2>(Action<T1, T2> action)
    {
        Converter<T1, FSharpFunc<T2, Unit>> conv = value1 =>
        {
            return FuncConvert.ToFSharpFunc<T2>(value2 => action(value1, value2));
        };

        return FSharpFunc<T1, FSharpFunc<T2, Unit>>.FromConverter(conv);
    }
}     

Тогда вы можете сделать это:

var func = FuncConvertExt.Create<string, string>(Print);
func.Invoke("aaa").Invoke("bbb");

Дополнительная информация: https://blogs.msdn.microsoft.com/jaredpar/2010/07/27/converting-system-funct1-tn-to-fsharpfuncttresult/