2016-12-26 20 views
5

Tworzę aplikację F#.net 4.6.1 pod numerem VS2015. Mam metody:Metoda F # zwraca wartość null zamiast opcji

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)) 

Ale kiedy wywołanie tej metody i otrzymać null zamiast option. enter image description here Co robię źle?

+2

Moje przypuszczenie - problem związany z 'visual studio 2015'. Ponieważ logika biznesowa działa dobrze, myślę, że interfejs użytkownika "VS2015" pokazuje niepoprawne informacje – burzhuy

+2

Miałem domyślną wartość dla tego typu pojawia się podczas przechodzenia - "domyślnie (T)" w przypadku typów wartości i "null" dla typów odniesienia. – Asti

Odpowiedz

9

W języku F # można reprezentować jedną bezinformacyjną wartość DU ze stałą null w czasie wykonywania. Można polecić kompilator to zrobić z CompilationRepresentationFlags.UseNullAsTrueValue:

[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] 
type A = B | C of int 

printfn "%A" (obj.ReferenceEquals(B, null)) // will print "true" 

W powyższym kodzie, wartość DU B zostanie skompilowany do null. Czasem jest to miłe z punktu widzenia optymalizacji: zamiast przydzielać instancję za każdym razem, używam stałej. Pomaga, jeśli wartość jest często używana.

Więc typ Option wykorzystuje tę samą technikę przypadku None i dlatego None pokazuje się jako null w debugger.

Pewnego dnia debugger będzie miał odpowiednie punkty rozszerzeń do implementacji tego i innych funkcji F #. Do tego czasu debugger mówi w języku C#, a ty wykonujesz tłumaczenie.

+2

Debugger pracował dobrze przed VS2015, co się stało? – scrwtp

+1

Mówisz, że przed 2015 r. Debugger pokazał ci 'Brak' zamiast' null'? Czy jesteś absolutnie pewien? –

+1

Właśnie sprawdziłem i masz rację. Musiałam mentalnie zastąpić 'Nones' dla' nulls'. – scrwtp

Powiązane problemy