在我看来,F#选项类型的某些属性在C#项目中是不可见的。通过检查类型,我可以看到或多或少的原因,但我不能真正理解究竟发生了什么,为什么做出这些选择或如何最好地规避问题。
这里有一些片段展示了这个问题。我有一个包含两个项目的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错误&#34;语言&#34;不支持属性,索引器或事件......与此一致,Intellisense没有检测到属性:
现在,在检查FSharpOption类型时,我可以看到IsNone和IsSome&#34;属性&#34;显示为静态方法:
另一方面,当我从F#检查类型时,我看到以下内容:
在这里,&#34;存在&#34;属性IsSome
和IsNone
很明显。将光标悬停在这些属性上,VS2015给出了以下注释:&#34;包含类型可以使用&#39; null&#39;作为其结合工会案件的代表价值。该成员将被编译为静态成员。&#34;这就是除了静态方法(如lukegv和Fyodor Soikin所述)之外,这些属性不可用的原因。
因此,情况似乎如下:编译的FSharpOption类型没有任何IsNone和IsSome属性。 F#中的幕后工作正在进行,以启用模拟这些属性的功能。
我知道我可以通过使用Microsoft.FSharp.Core中的OptionModule
来解决这个问题。但是,似乎这个功能是F#核心库的架构师有意识的选择。选择的原因是什么?并且正在使用OptionModule
正确的解决方案,还是有更好的方法来使用C#中的FSharpOption<T>
类型?
答案 0 :(得分:10)
这与a1.sources = r1 r2
a1.sinks = k1 k2
a1.channels = c1 c3
#sources
a1.sources.r1.type=netcat
a1.sources.r1.bind=localhost
a1.sources.r1.port=4444
a1.sources.r2.type=exec
a1.sources.r2.command=tail -f /opt/gen_logs/logs/access.log
#sinks
a1.sinks.k1.type=hdfs
a1.sinks.k1.hdfs.path=/flume201
a1.sinks.k1.hdfs.filePrefix=netcat-
a1.sinks.k1.rollInterval=100
a1.sinks.k1.hdfs.fileType=DataStream
a1.sinks.k1.hdfs.callTimeout=100000
a1.sinks.k2.type=hdfs
a1.sinks.k2.hdfs.path=/flume202
a1.sinks.k2.hdfs.filePefix=execCommand-
a1.sinks.k2.rollInterval=100
a1.sinks.k2.hdfs.fileType=DataStream
a1.sinks.k2.hdfs.callTimeOut=100000
#channels
a1.channels.c1.type=file
a1.channels.c1.checkpointDir=/home/cloudera/alpha/001
a1.channels.c3.type=file
a1.channels.c3.checkpointDir=/home/cloudera/beta/001
#bind r1 c1 k1
a1.sources.r1.channels=c1
a1.sinks.k1.channel=c1
a1.sources.r2.channels=c3
a1.sinks.k2.channel=c3
的编译方式有关。 Channel closed [channel=c3]. Due to java.io.IOException: Cannot lock /home/cloudera/.flume/file-channel/data. The directory is already locked. [channel=c3]
值可以直接编译为创建类的实例并将值包装在其中。但option
值并非真正的值,它们只是Some
。
试试这个:
None
(这也是null
值will show up as null
in the debugger's Watch window)
这是一种在运行时节省大量周期的优化。 (并且您可以通过应用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
进行所有操作。
至于为什么这些属性不会出现在intellisense中 - 那是因为它们是null
。虽然我不确定他们为什么会在那里出现。也许是编译器工件。
答案 1 :(得分:3)
我不熟悉F#,但由于它都是CLR,我的答案来自C#的观点:
在生成的类定义中,IsNone
和IsSome
都是静态的,因此无法通过实例optionType
访问(既不通过IntelliSense也不通过代码)。属性Value
不是静态的,可以访问。