У меня есть следующая функция 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/