参考F# - On the parameters passed to C# methods - are they tuples or what?,当从F#调用C#方法时,参数作为语法元组提供。
我的理解是必须以这种方式调用C#方法。所以从这个问题中举例说明,
MyClsas.Add(4, 5) |> printfn "%d"
正常工作,而
MyClsas.Add 4 5 |> printfn "%d"
会给出错误
This value is not a function and cannot be applied
This expression was expected to have type
int * int
but here has type
int
因此,我的问题是,F#如何知道它是一个被调用的C#方法,并且需要语法元组?
答案 0 :(得分:3)
我的F#扩展程序集元数据以支持功能概念。考虑一下:
module MyModule =
let curried x y z = x*y + z
let tupled (x,y,z) = x*y + z
MyModule反编译:
[CompilationArgumentCounts(new int[]
{
1,
1,
1
})]
public static int curried(int x, int y, int z)
{
return x * y + z;
}
public static int tupled(int x, int y, int z)
{
return x * y + z;
}
因此,似乎F#以属性的形式添加了额外的元数据,以帮助F#编译器实现curried
与tupled
不同。但是使用CompiliationArgumentCounts扩展C#方法并不起作用(我试过)。似乎F#以两个名为FSharpSignatureData.Curry
和FSharpOptimizationData.Curry
的汇编资源的形式添加了更多元数据。
C#并不知道这个元数据,因此curried
和tupled
的签名在C#中是相同的。
如果你是好奇的话,小费;下载一个很好的.NET反编译器(有很多)。通过反编译为IL或C#,您经常会学到很多语言功能的实际实现方式以及它们带来的隐藏成本。
答案 1 :(得分:1)
这是因为对非F#库的方法调用无法进行调整;事实上,来自非F#库的方法就好像它们采用了一组参数。这就是为什么你必须调用BCL方法传递在元组中分组的参数的原因。
正如我所说,在汇编F#代码时会发生评论。这意味着编译器已根据需要确保每个函数只有一个参数。因此,您可以逐个传递一个参数,这是一个部分应用程序。从@FuleSnabel显示的反编译代码中,我们可以看到属性Core.CompilationArgumentCountsAttribute
。在msdn(https://msdn.microsoft.com/fr-fr/library/ee353833.aspx)上,您可以阅读以下内容:
编译器在内部使用它来指示函数或成员接受其某些参数的部分应用并返回残差函数。