문제

In F#, we can create a function like this:

let ``add x and y`` x y = x + y

And I can call it normally like this:

``add x and y`` 1 2

Is there a way to call the function above from C# side? I couldn't even see it in Object Browser though.

도움이 되었습니까?

해결책

You can expose any valid F# function name to C# as any C# valid function name using CompiledName attribute:

namespace Library1
module Test = 
    [<CompiledName("Whatever")>]
    let ``add a and b`` x y = x + y

and then in C#:

 using Library1;
 ...............
 System.Console.WriteLine(Test.Whatever(2,2));

FOLLOW-UP 03/05/2016 on comment from NickL, applies at least to F#3.1:

Moving from functions to members brings some "ifs and buts".

To begin with, CompiledName attribute does not compile with member if being used from pure namespace. The mere compilation requires use within a module.

When being used within a module and decorating method member of F# record it works just fine regardless of how the contents between two ticks looks. However when decorating property member of F# record CompiledName is visible cross-assembly only if contents between double ticks resembles some legal value name:

module M

type MyRecord =
    { myField: string }
    [<CompiledName "Whatever">]
    member x.``Blah Blah blah``() = x.myField
    [<CompiledName "Another">]
    member x.``ABC`` = x.myField

and then from C# the following works OK:

var recInC = new M.MyRecord("Testing...");
Console.WriteLine(recInC.Whatever());
Console.WriteLine(recInC.Another);

Such inconsistencies prompt for potential issues.

다른 팁

Reflection might be the only way, but it doesn't have to be ugly to use. Just wrap it all within a class to do the reflecting.

public static class MyModuleWrapper
{
    // it would be easier to create a delegate once and reuse it
    private static Lazy<Func<int, int, int>> addXAndY = new Lazy<Func<int, int, int>>(() =>
        (Func<int, int, int>)Delegate.CreateDelegate(typeof(Func<int, int, int>), typeof(MyModule).GetMethod("add x and y"))
    );
    public static int AddXAndY(int x, int y)
    {
        return addXAndY.Value(x, y);
    }

    // pass other methods through.
    public static int OtherMethod(int x, int y)
    {
        return MyModule.OtherMethod(x, y);
    }
}

Then use it like normal.

var sum = MyModuleWrapper.AddXAndY(1, 2);
var otherValue = MyModuleWrapper.OtherMethod(1, 2); // use the wrapper instead

I'm not sure what needs to be changed or how if there are polymorphic types involved, but hopefully you get the idea and can apply the necessary changes.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top