如何解决关于out和tuple形式的这个互操作问题?

时间:2013-01-25 01:26:07

标签: f#

我在F#中创建了一个函数

let tryParseArray tryParse (separator:char) (line: string) =
    // inside the function I use the tuple form of tryParse

如果我以这种方式调用它,它可以正常工作:tryParseArray Int32.TryParse ',' "2,3,2,3,2"

现在我希望这个函数也可以在C#中使用,所以我这样做了:

static member TryParseArray (line, tryParse, separator) =
    line |> tryParseArray tryParse separator

然后我意识到TryParseArray实际上将tryParse参数视为FSharpFunc,这对C#一点都不友好,所以我尝试了这个:

static member TryParseArray (line, [<Out>] tryParse: (string * byref<'a> -> bool), separator) =
    line |> tryParseArray tryParse separator

但现在tryParseArray不接受tryParse作为有效参数(类型错误)

我该怎么办?

我希望在C#中我也可以拨打TryParseArray("2,3,2,3,2", Int32.TryParse, ',')

2 个答案:

答案 0 :(得分:5)

您可以使用自定义委托类型将此函数公开给C#:

<强> EDITED

// F#
module Lib

let tryParseArray parser (line : string) (sep : char) = 
    // don't know your exact implementation so again just guessing...
    line.Split sep
    |> Array.choose (fun el ->
        match parser el with
        | true, el -> Some el
        | false, _ -> None
        )

open System.Runtime.InteropServices
type TryParse<'R>  = delegate of str : string * [<Out>] res : byref<'R> -> bool

type T = 
    static member TryParse(line : string, tryParse : TryParse<'R>, separator : char) : 'R[] = 
        tryParseArray tryParse.Invoke line separator


 //C# 
 var r = Lib.T.TryParse<int>("1,2,3", int.TryParse, ',');

注意:在C#端,您需要明确指定TryParse的类型参数(Why don't anonymous delegates/lambdas infer types on out/ref parameters?

答案 1 :(得分:0)

desco的解决方案很好,但是如果你想避免byref你可以做这样的事情:

type TryParse<'R>  = delegate of string -> bool * 'R

module Util =
  [<CompiledName("TryParseArray")>]
  let tryParseArray (tryParse: TryParse<_>) (separator:char) (line: string) = ...

可以从F#调用,如下所示:

let res = Util.tryParseArray (TryParse(Int32.TryParse)) ',' "1,2,3"

并使用以下包装方法:

static class TryParse {
    public static Tuple<bool, int> Int32(string s) {
        int i;
        var b = System.Int32.TryParse(s, out i);
        return Tuple.Create(b, i);
    }
}
像这样,来自C#:

var res = Util.TryParseArray(TryParse.Int32, ',', "1,2,3");