I want to write a function in F#, that exposes the following t开发者_C百科ype signature to C#:
public static FSharpFunc<FSharpFunc<Unit,Unit>,Unit> foo(Action<Action> f)
In F# I tried writing:
let foo (f : Action<Action>) : ((unit -> unit) -> unit) = ...
But that produces the C# signature:
public static void foo(Action<Action> f, FSharpFunc<Unit,Unit> x)
The F# has treated my code equivalently to:
let foo (f : Action<Action>) (g : unit -> unit) : unit = ...
Of course, these are equivalent to F#, but very different in C#. Is there anything I can do to produce the C# I want? (F# 2.0.0.0)
As a quick hack, I rewrote my F# to:
let foo (f : Action<Action>) ((unit -> unit) -> unit)[] = ...
Then I just use Head
in the C#.
If you write let foo x = fun () -> ...
then the F# compiler optimizes the code and compiles it as a method that takes two arguments (instead of a method returning function which is what you need). To get a function value as the result, you need to "do something" before returning the function:
// Will be compiled as method taking Action, FastFunc and returning void
let foo1(x : Action<Action>) : (unit -> unit) -> unit =
fun f -> f ()
// Will be compiled as method taking Action and returning FastFunc of FastFunc
let foo2(x : Action<Action>) : ((unit -> unit) -> unit) =
ignore ();
fun f -> f ()
That said, exposing F# function type to C# in any way is a bad pattern and it shouldn't be done. When you have some F# API that is supposed to be used from C#, you should expose functions as delegates, so that C# consumers can use them naturally (without converting Action
to F# function explicitly). It is generally easier to write the wrapping on the F# side.
Either:
- Add a signature file, with
val foo : Action<Action> -> ((unit -> unit) -> unit)
. - Use a static member of a nominal type, rather than a let-bound value in a module. That is,
static member foo (x:Action<Action>) : ((unit -> unit) -> unit) = ...
something like this?
open System
let foo(x : Action<Action>) : (unit -> unit) -> unit = failwith "..."
精彩评论