gpt4 book ai didi

c# - F# - 关于传递给 C# 方法的参数 - 它们是元组还是什么?

转载 作者:IT王子 更新时间:2023-10-29 04:43:33 25 4
gpt4 key购买 nike

我看过很多次

Assemblies generated from F# or any other .NET language are (almost) indistinguishable.

然后我在 .NET 4(测试版 2)上试验 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!)

到目前为止一切顺利。然后我想到了我读过很多次(可能在不同的书上)的另一句话:

When passing arguments to functions from other .NET libraries, you use a syntax like ".MethodName(parm1, parm2)", that is, the parameters are passed as a Tuple.

将其添加到我曾经在 SO 上阅读过的内容(但无法找到它的链接),关于 OP 试图创建类似 [ 4, 5, 6 ] 的问题(当他指的是 [4; 5; 6] 时):

"Comma is the 'tuple creating operator', for everything else use semi-colon."

然后我将我的类(class)修改为以下内容:

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# 将无法编译,因为 Addint -> int -> int ,而不是 (int * int) -> int .

发生了什么?!?

最佳答案

When passing arguments to functions from other .NET libraries, you use a syntax like ".MethodName(parm1, parm2)", that is, the parameters are passed as a Tuple.

比这更可怕。请参阅来自 language spec 的方法重载决议海峡的描述.

基本上,它说的是方法调用中的参数并不是真正的元组。这是一个句法元组,意思是用逗号分隔的列表,但是括号是方法调用语法的一部分,逗号也是。这就是为什么,例如 o.M(a=1, b=2)不是带有两个 bool 值元组的方法调用,而是两个命名参数。

因此,通常情况下,每个逗号分隔的组件只映射到一个不同的参数。因此为什么 Add(1, 2)电话 Add(int, int)过载,和Add((1, 2))电话 Add(Tuple<int, int>) .这里没有歧义。

但是,针对您的特定情况的特殊情况是:

If there are no named actual arguments, and there is only one candidate method in M, accepting only one non-optional argument, then the decomposition of arg to tuple form is ignored and there is one named actual arg which is arg itself.

因此,当您删除除元组重载之外的所有重载时,括号内的整个内容突然被有效地视为调用中的元组构造函数。但是如果你愿意有两个重载,Add(int)Add(Tuple<int,int>) , 然后是 Add(1,2) 形式的调用根本无法解决。

关于c# - F# - 关于传递给 C# 方法的参数 - 它们是元组还是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2025845/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com