F#方法返回null而不是Option

6

我在VS2015上开发基于.net 4.6.1F#应用程序。我有以下几种方法:

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而不是optionenter image description here 我做错了什么?


2
我的猜测是,这个问题与Visual Studio 2015有关。因为业务逻辑运行良好,我认为VS2015的用户界面显示了不正确的信息。 - Maxim Kitsenko
2
当我进行步进操作时,该类型的默认值会出现 - 对于值类型是 default(T),对于引用类型是 null - Asti
1个回答

11

在 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#,所以您需要翻译一下。

2
调试器在VS2015之前一直很好用,发生了什么事? - scrwtp
1
你是说在2015年之前,调试器显示的是None而不是null?你确定吗? - Fyodor Soikin
1
刚刚检查了一下,你是对的。我可能一直在脑子里将“Nones”替换为“nulls”。 - scrwtp
问题报告在这里:https://developercommunity.visualstudio.com/content/problem/44030/f-debugging-option-types-returns-null.html 和 https://github.com/Microsoft/visualfsharp/issues/3716 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接