为什么 FSharpOption 的某些属性(例如 IsSome 和 IsNone)在 C# 中不可见?

Why are some properties (e.g. IsSome and IsNone) for FSharpOption not visible from C#?

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

以下是演示该问题的一些片段。我有一个包含两个项目的 VS2015 解决方案,一个 C# 项目和一个 F# 项目。在F#项目中,我有一个class定义如下:

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# 项目中使用选项类型时,我通常可以访问 IsSomeIsNone 属性。但是,当我尝试编写类似 optionType.IsNone 的内容时,我收到 CS1546 错误 "Property, indexer or event ... is not supported by the language"。与此一致,Intellisense 不检测 属性:

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

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

这里,属性IsSomeIsNone的"existence"就很明显了。将光标悬停在这些属性上,VS2015 给了我以下注释:"The containing type can use 'null' as a representation value for its nullary union case. This member will be compiled as a static member." 这就是为什么属性不可用的原因,除了静态方法(如 lukegv 和 Fyodor Soikin 所指出的)。

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

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

我对F#不是很了解,但是因为都是CLR,所以我的回答是从C#的角度:

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

这与 option 的编译方式有关。 Some 值直接编译为创建 class 的实例并将值包装在其中。但是 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 的原因)

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

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

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