【发布时间】:2019-04-04 20:14:42
【问题描述】:
如果我创建一个新的匿名记录,例如,我可以看到。
let myRecord = {| SomeInteger = 5 |}
如果它暴露在 C# 中,那么我可以用
var someInteger = myRecord.SomeInteger;
反过来呢,如果我有一个 F# 函数,说:
let unwrap (record : {| SomeInteger : int |}) = record.SomeInteger
它暴露给 C#,我如何从 C# 实例化这个函数的参数并调用它?我天真地尝试在那里放置一个 C# 匿名类型,即。
var unwrapped = unwrap(new { SomeInteger = 5 });
但这没有编译。我在RFC for the feature 中注意到,“该功能必须实现与 C# 匿名对象的兼容性(来自 C# 3.0)”,但没有具体提到具体采用何种方式。支持吗?
【问题讨论】:
-
“没有给出额外的细节”? RFC 在该声明之后的行中解释了兼容性要求直接指的内容。如果您不能利用 F# 类型推断,则无法创建此类类型的实例,因为作为 anonymous 类型,它们没有可以引用它们的真实名称,而 C# 没有在方法范围之外使用匿名类型的方法。
-
我建议在 ILSpy(或您喜欢的任何此类工具)中打开生成的 F# 构建程序集,并查看为
myRecord生成的类型。这应该会告诉您很多关于实现兼容性的方式。 -
是的,我有点含糊,我会更新这个问题。也许我理解错了,但在我看来,后面的几行似乎描述了实现与 C# 匿名类型的共同点,而不是它们如何互操作。我不确定类型推断是否是这里的问题 - C# 编译器可以读取生成的类型并知道如何编译匹配的匿名类型或 ValueTuple 文字(好的,所以我猜这不是 F# 功能本身待定)。我喜欢这个功能,但如果我们不能使用从 C# 接收它们的函数,那么将“互操作”作为设计目标似乎有点奇怪。
-
我不确定在这种情况下“互操作”的范围是什么。问题是:C# 中的匿名类型仅基于方法范围内的类型推断创建,并且它们没有名称。要在 C# 中创建类型的实例,您需要它的名称/构造函数,或者它必须是本地匿名类型。对于匿名 F# 类型,C# 的功能将不会超过这一点——它们仍然没有您可以用来创建它们的名称。您可以做的是从 F# 函数返回一条匿名记录,然后使用
var将其绑定到 C# 中的变量并访问其字段。