Вызовите функциональное имя F # с внедренными пространствами (`` XXX YY``) из С#

В F # мы можем создать такую ​​функцию:

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

И я могу назвать это обычно следующим образом:

``add x and y`` 1 2

Есть ли способ вызвать функцию выше со стороны С#? Я даже не видел его в обозревателе объектов.

Ответ 1

Вы можете выставить любое valid имя функции F # на С# как любое имя функции С# с использованием атрибут CompiledName:

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

а затем в С#:

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

FOLLOW-UP 03/05/2016 в комментарии от NickL применяется, по крайней мере, к F # 3.1:

Переход от функций к членам приводит к некоторым "ifs и buts".

Для начала атрибут CompiledName не компилируется с помощью member, если используется с чистым namespace. Для простой компиляции требуется использовать в пределах module.

При использовании в module и методе декорирования member записи F # он работает отлично, независимо от того, как выглядит содержимое между двумя тиками. Однако, когда украшающее свойство member записи F # CompiledName видится кросс-сборкой, только если содержимое между двойными тиками напоминает какое-то правовое значение:

module M

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

а затем из С# выполняется следующее:

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

Такие несоответствия требуют потенциального issues.

Ответ 2

Отражение может быть единственным способом, но он не должен быть уродливым в использовании. Просто оберните все это внутри класса, чтобы сделать отражение.

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);
    }
}

Затем используйте его как обычно.

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

Я не уверен, что нужно изменить или как, если есть полиморфные типы, но, надеюсь, вы получите эту идею и можете применить необходимые изменения.