【问题标题】:Call F# function from C# passing function as a parameter从 C# 传递函数作为参数调用 F# 函数
【发布时间】:2018-04-15 21:47:24
【问题描述】:

我有以下 F# 函数

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

在我的 C# 类中,我想调用 Fetch F# 函数来模拟 logger 函数。 所以我有以下 C# 函数作为 mocker。

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

我正在尝试使用以下代码从 C# 类调用 F# 函数。

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

FuncConvert.ToFSharpFunc 的问题在于它只接受一个类型参数。 当我将 Fetch F# logger 函数更改为以下内容时,当我使用 ToFSharpFunc(Print) 其中 C# Print 函数也接受一个字符串时,它可以正常工作。

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

有人有想法吗?

【问题讨论】:

    标签: c# f#


    【解决方案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# 函数只接受一个参数。多个参数本质上创建嵌套函数。你需要在 C# 方面做同样的事情。

    使用 Intellisense 检查 C# 中 logger 参数的类型。这是

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

    FuncConvert.ToFSharpFunc 不能创建这个。 FuncFromTupled 虽然可以从 FSharpFunc 创建它,该 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 的描述所说,它是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/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-09
        • 1970-01-01
        相关资源
        最近更新 更多