F# 方法 returns null 而不是 Option
F# method returns null instead of Option
我在 VS2015
上开发 F#
应用程序 .net 4.6.1
。我有方法:
type CommonHelper =
static member SideEffectOnNull act x = if x = null then act(); x else x
static member SideEffectOnNotNull act x = if x <> null then act(); x else x
...
static member GetPerformanceCounter ( fname: CounterFullName ) =
let getCounterInternal ( counterFullName: CounterFullName ) =
Log.Information("Getting counter: {category}\{name}\{instance} ", counterFullName.Category, counterFullName.Name, counterFullName.Instance)
let receivedCategory = PerformanceCounterCategory.GetCategories().FirstOrDefault( fun x -> String.Equals( x.CategoryName, counterFullName.Category.Category, StringComparison.InvariantCultureIgnoreCase ) )
if receivedCategory = null then
Serilog.Log.Warning ( "Category not found: {category}", counterFullName.Category ); null
else
let receivedCounters = PerforrmanceCounterProxy.GetPerformanceCountersFromCategoryOrNull counterFullName.Instance receivedCategory
if receivedCounters = null then
Log.Warning ("Instance not found {name}(instance: {instance}) in category {category}", counterFullName.Name, counterFullName.Instance, counterFullName.Category); null
else
receivedCounters.FirstOrDefault( fun y -> String.Equals( y.CounterName, counterFullName.Name.Name, StringComparison.InvariantCultureIgnoreCase ) )
|> CommonHelper.SideEffectOnNull ( fun unit -> Log.Warning ("Name {name}(instance: {instance}) not found for category {category}", counterFullName.Name, counterFullName.Instance, counterFullName.Category) )
getCounterInternal fname
|> CommonHelper.SideEffectOnNull (fun unit ->Log.Warning( "Getting counter failed: {category}\{name}\{instance}", fname.Category, fname.Name, fname.Instance ))
|> CommonHelper.SideEffectOnNotNull (fun unit ->Log.Information( "Getting Counter secceed: {category}\{name}\{instance}", fname.Category, fname.Name, fname.Instance ))
|> (fun x -> if x = null then None else Option.Some(x))
但是当我调用此方法时,我收到 null
而不是 option
。
我做错了什么?
在 F# 中,可以在运行时用 null
常量表示 DU 的一个无数据值。您可以指示编译器使用 CompilationRepresentationFlags.UseNullAsTrueValue
:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type A = B | C of int
printfn "%A" (obj.ReferenceEquals( B, null )) // will print "true"
在上面的代码中,DU 值 B
被编译为 null
。有时这对于优化目的很有好处:我不是每次都分配一个实例,而是使用一个常量。如果该值被大量使用,会有帮助。
所以 Option
类型对 None
情况使用相同的技术,这就是 None
在调试器中显示为 null
的原因。
总有一天,调试器将有适当的扩展点来实现此功能和其他 F# 功能。在那之前,调试器会说 C#,而你可以进行翻译。
我在 VS2015
上开发 F#
应用程序 .net 4.6.1
。我有方法:
type CommonHelper =
static member SideEffectOnNull act x = if x = null then act(); x else x
static member SideEffectOnNotNull act x = if x <> null then act(); x else x
...
static member GetPerformanceCounter ( fname: CounterFullName ) =
let getCounterInternal ( counterFullName: CounterFullName ) =
Log.Information("Getting counter: {category}\{name}\{instance} ", counterFullName.Category, counterFullName.Name, counterFullName.Instance)
let receivedCategory = PerformanceCounterCategory.GetCategories().FirstOrDefault( fun x -> String.Equals( x.CategoryName, counterFullName.Category.Category, StringComparison.InvariantCultureIgnoreCase ) )
if receivedCategory = null then
Serilog.Log.Warning ( "Category not found: {category}", counterFullName.Category ); null
else
let receivedCounters = PerforrmanceCounterProxy.GetPerformanceCountersFromCategoryOrNull counterFullName.Instance receivedCategory
if receivedCounters = null then
Log.Warning ("Instance not found {name}(instance: {instance}) in category {category}", counterFullName.Name, counterFullName.Instance, counterFullName.Category); null
else
receivedCounters.FirstOrDefault( fun y -> String.Equals( y.CounterName, counterFullName.Name.Name, StringComparison.InvariantCultureIgnoreCase ) )
|> CommonHelper.SideEffectOnNull ( fun unit -> Log.Warning ("Name {name}(instance: {instance}) not found for category {category}", counterFullName.Name, counterFullName.Instance, counterFullName.Category) )
getCounterInternal fname
|> CommonHelper.SideEffectOnNull (fun unit ->Log.Warning( "Getting counter failed: {category}\{name}\{instance}", fname.Category, fname.Name, fname.Instance ))
|> CommonHelper.SideEffectOnNotNull (fun unit ->Log.Information( "Getting Counter secceed: {category}\{name}\{instance}", fname.Category, fname.Name, fname.Instance ))
|> (fun x -> if x = null then None else Option.Some(x))
但是当我调用此方法时,我收到 null
而不是 option
。
在 F# 中,可以在运行时用 null
常量表示 DU 的一个无数据值。您可以指示编译器使用 CompilationRepresentationFlags.UseNullAsTrueValue
:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type A = B | C of int
printfn "%A" (obj.ReferenceEquals( B, null )) // will print "true"
在上面的代码中,DU 值 B
被编译为 null
。有时这对于优化目的很有好处:我不是每次都分配一个实例,而是使用一个常量。如果该值被大量使用,会有帮助。
所以 Option
类型对 None
情况使用相同的技术,这就是 None
在调试器中显示为 null
的原因。
总有一天,调试器将有适当的扩展点来实现此功能和其他 F# 功能。在那之前,调试器会说 C#,而你可以进行翻译。