【问题标题】:Why are some properties (e.g. IsSome and IsNone) for FSharpOption not visible from C#?为什么 FSharpOption 的某些属性(例如 IsSome 和 IsNone)在 C# 中不可见?
【发布时间】:2017-02-01 15:34:10
【问题描述】:

在我看来,F# 选项类型的某些属性在 C# 项目中是不可见的。通过检查类型,我或多或少可以看出原因,但我并不真正了解究竟发生了什么,为什么做出这些选择或如何最好地规避问题。

这里有一些 sn-ps 演示了这个问题。我有一个 VS2015 解决方案,其中包含两个项目,一个 C# 项目和一个 F# 项目。在 F# 项目中,我有一个类定义如下:

type Foo () =

    member this.Bar () = Some(1)

此外,在 F# 中我可以这样写:

let option = (new Foo()).Bar()
let result = if option.IsNone then "Is none" else "Is some"

所以看起来选项类型有一个名为IsNone 的属性。现在,在 C# 项目中,我引用了从 F# 项目编译的 .dll。这让我可以写例如

var optionType = new Foo().Bar();

变量optionType 是FSharpOption<int>。如上所述,当我在 F# 项目中使用选项类型时,我通常可以访问例如 IsSome 和 IsNone 属性。但是,当我尝试编写 optionType.IsNone 之类的内容时,我收到 CS1546 错误“语言不支持属性、索引器或事件 ...”。与此一致,Intellisense 不会检测到该属性:

现在,在检查 FSharpOption 类型时,我可以看到 IsNone 和 IsSome “属性”显示为静态方法:

另一方面,当我从 F# 检查类型时,我看到的是以下内容:

在这里,属性IsSome 和IsNone 的“存在​​”是显而易见的。将光标悬停在这些属性上,VS2015 给了我以下注释:“包含类型可以使用 'null' 作为其空联合情况的表示值。该成员将被编译为静态成员。”这就是为什么这些属性除了作为静态方法之外不可用的原因(正如 lukegv 和 Fyodor Soikin 所指出的那样)。

因此,情况似乎如下:编译后的 FSharpOption 类型没有任何 IsNone 和 IsSome 属性。 F# 的幕后正在发生一些事情,以启用模拟这些属性的功能。

我知道我可以通过在 Microsoft.FSharp.Core 中使用 OptionModule 来解决这个问题。然而,这个功能似乎是 F# 核心库的架构师有意识的选择。选择的原因是什么?并且使用 OptionModule 是正确的解决方案,还是有更好的方法来使用 C# 中的 FSharpOption<T> 类型?

【问题讨论】:

    标签: c# properties f# interop


    【解决方案1】:

    这与option 的编译方式有关。 Some 值被直接编译为创建类的实例并将值包装在其中。但是None 的值并不是真正的值,它们只是null。

    试试这个:

    let a: int option = Some 1
    let b: int option = None
    let a_isNull = obj.ReferenceEquals( a, null )   // a_isNull = false
    let b_isNull = obj.ReferenceEquals( b, null )   // b_isNull = true
    

    (这也是None值will show up as null in the debugger's Watch window的原因)

    这是一项优化,可在运行时节省大量周期。 (您也可以通过应用CompilationRepresentationFlags.UseNullAsTrueValue 将其用于您自己的联合类型)

    现在,由于这种类型的某些值可能是null,因此您不能真正对这些值使用属性或方法。如果该值恰好是null,你就会崩溃。这就是为什么您应该始终使用OptionModule 进行所有操作。

    至于为什么这些属性没有出现在智能感知中 - 那是因为它们是 static。虽然我不确定他们为什么会出现在那里。也许是编译器工件。

    【讨论】:

    • 谢谢,None 值确实为空这一事实很好地解释了为什么要删除 IsNone 和 IsSome 属性。我已经对问题进行了一些编辑,以包含您的问题和 lukegv 的评论,即在编译的类中,“属性”是静态的。
    • Sooo... 你还没有了解机制和原因吗?还有什么不清楚的吗?
    • 啊。我有点困惑为什么你还没有接受答案,但是在我写完评论之后你就接受了。
    • 有一个静态的IsSome 方法,是的,但是实例上还有一个属性see source。它在 F# 中可用,在 Intellisense 中可见。为什么不在 C# 端?是的,您可以争辩说它们会在null/None 上造成麻烦,但是为“外部世界”删除它们的机制是什么?
    • 该属性只是 F# 意义上的属性,而不是 CLR 意义上的属性。在底层 IL 中,没有属性。
    【解决方案2】:

    我对F#不是很精通,但是既然都是CLR,我的回答是从C#的角度:

    在生成的类定义中,IsNone 和 IsSome 都是静态的,因此无法通过实例 optionType 访问(既不能通过 IntelliSense,也不能在代码中)。 Value 属性不是静态的,可以访问。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      相关资源
      最近更新 更多