从 C# 调用带有嵌入空格的 F# 勾选函数名称 (“XXX YY”)

本文关键字:函数 XXX YY 调用 空格 | 更新日期: 2023-09-27 18:35:12

在F#中,我们可以创建一个这样的函数:

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

我可以像这样正常地称呼它:

``add x and y`` 1 2

有没有办法从 C# 端调用上面的函数?不过,我什至无法在对象浏览器中看到它。

从 C# 调用带有嵌入空格的 F# 勾选函数名称 (“XXX YY”)

可以使用 CompiledName 属性将任何有效的 F# 函数名称作为任何 C# 有效函数名称向 C# 公开:

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

然后在 C# 中:

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

跟进 03/05/2016 关于 NickL 的评论,至少适用于 F#3.1:

从函数到成员的移动会带来一些"如果和但是"。

首先,如果从纯namespace使用CompiledName属性,则不会使用 member 进行编译。单纯的编译需要在module中使用。

在 F# 记录member module和装饰方法中使用时,无论两个刻度之间的内容看起来如何,它都可以正常工作。但是,在装饰 F# 记录的属性member时,仅当双引号之间的内容类似于某些合法值名称时,CompiledName的交叉程序集才可见:

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

然后从 C# 开始,以下工作正常:

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

这种不一致会引发潜在的问题。

反射可能是唯一的方法,但它不一定是丑陋的。 只需将其全部包装在一个类中即可进行反射。

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

我不确定需要更改什么或是否涉及多态类型,但希望您能理解并可以应用必要的更改。