我已经多次阅读到:
使用F#或其他.NET语言生成的程序集(几乎)无法区分。
我当时在.NET 4(beta2)上尝试使用F#和C#互操作。 我创建了一个新解决方案和一个C#项目,并编写了以下类:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
}
然后,在一个F#项目中引用了C#项目之后,我尝试了以下操作:
MyClsas.Add(4, 5) |> printfn "%d" // prints 9 (no kidding!)
到目前为止,一切都很顺利。然后,我想起了另一个我已经多次读到的句子(或许在不同的书本上):当从其他 .NET 库传递参数给函数时,你使用的语法是 ".MethodName(parm1, parm2)",也就是说,参数作为 Tuple 传递。
再加上我曾经在这里(指 StackOverflow)读过一些东西(但无法找到链接),有人在一个问题中尝试创建像
[4, 5, 6]
这样的 using(当他的意思是 [4; 5; 6]
):“逗号是 'tuple creating operator',对于其他所有情况,请使用分号。”
然后我将我的类修改为以下内容:
public class MyClass {
public static int Add(int a, int b) { return a + b; }
public static int Add(Tuple<int, int> a) { return a.Item1; }
}
现在我尝试在F#上使用它:
MyClass.Add(4, 5) |> printf "%d" // prints ... (keep reading!)
因此,综合以上三个引用,可以得出以下结论:- F#在看到
(4,5)
时将创建一个元组。
- 然后它将调用重载的Add(Tuple<int,int>)
。
- 所以它会打印4。让我惊讶的是,它打印了9。这不是很有趣吗?
这里实际上正在发生什么?上述引用和这些实际观察似乎相互矛盾。你能证明F#的“推理”,并可能指向一些MSDN文档吗?
谢谢!
编辑
(添加更多信息(来自Blindy的答案))
如果您执行:
MyClass.Add((4, 5)) |> printfn "%d" // prints 9
F# 调用了 Add(Tuple<int, int>)
重载。
然而,如果你创建了另一个 F# 项目(即另一个程序集),并使用以下代码:
namespace MyFSharpNamespace
type MyFShapClass = class
static member Add x y = x + y
end
您可以在C#中像这样使用它
public static void Main(string[] args) {
MyFSharpNamespace.MyFSharpClass.Add(4, 5);
}
现在,到此为止都很好。但是,当你尝试从F#中使用它(来自另一个项目,另一个程序集)时,你需要执行以下操作:
MyFSharpNamespace.MyFSharpClass.Add 4 5 |> printfn "%d"
如果您将参数传递为(4,5)
,F#将无法编译,因为Add
是int -> int -> int
,而不是(int * int) -> int
。发生了什么?
Add
是由F#创建的一个类的静态方法,它需要2个参数(并且将从C#中使用.Add(4, 5)
),那么F#将无法编译.Add(4, 5)
。 - Bruno ReisAdd(int,int)
声明,看看它是否会解析为元组版本吗? - BlindyAdd(int, int)
,那么 F# 就会愉快地将.Add(4, 5)
转发到 C# 的Add(Tuple<int, int>)
。 - Bruno Reis