为什么FS#不能从C#中看到FSharpOption的某些属性(例如IsSome和IsNone)?

Ale*_*kol 11 c# f# interop properties

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

这里有一些片段展示了这个问题.我有一个包含两个项目的VS2015解决方案,一个C#项目和一个F#项目.在F#项目中,我有一个类定义如下:

type Foo () =

    member this.Bar () = Some(1)
Run Code Online (Sandbox Code Playgroud)

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

let option = (new Foo()).Bar()
let result = if option.IsNone then "Is none" else "Is some"
Run Code Online (Sandbox Code Playgroud)

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

var optionType = new Foo().Bar();
Run Code Online (Sandbox Code Playgroud)

变量optionType是一个FSharpOption<int>.如上所述,当我在F#项目中使用选项类型时,我通常可以访问例如IsSomeIsNone属性.但是,当我尝试写类似的东西时optionType.IsNone,我得到CS1546错误"属性,索引器或事件......语言不支持".与此一致,Intellisense没有检测到属性:

Intellisense不会检测IsSome和IsNone属性

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

来自C#的FSharpOption类签名

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

来自F#的FSharpOption类签名

在这里,属性的"存在" IsSome,并IsNone可见一斑.将光标悬停在这些属性上,VS2015给出了以下注释:"包含类型可以使用'null'作为其nullary union case的表示值.该成员将被编译为静态成员." 这就是除了静态方法(如lukegv和Fyodor Soikin所述)之外,这些属性不可用的原因.

因此,情况似乎如下:编译的FSharpOption类型没有任何IsNone和IsSome属性.F#中的幕后工作正在进行,以启用模拟这些属性的功能.

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

Fyo*_*kin 10

这与如何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
Run Code Online (Sandbox Code Playgroud)

(这也是None将显示null在调试器的Watch窗口中的原因)

这是一种在运行时节省大量周期的优化.(你也可以通过申请将它用于你自己的工会类型CompilationRepresentationFlags.UseNullAsTrueValue)

现在,由于此类型的某些值可能存在null,因此您无法在这些值上使用属性或方法.如果值恰好是null,你就会崩溃.这就是为什么你应该总是使用OptionModulefor all操作.

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

  • 谢谢,None值实际上为null的事实很好地解释了为什么删除了IsNone和IsSome属性.我已经编辑了一些问题,包括你和lukegv的评论,在编译的类中,"属性"是静态的. (3认同)