2009-06-03 10 views
19

¿Cuál es la forma correcta de utilizar Nullable en F #?F #: Nullable <T> Soporte

Actualmente estoy usando esto, pero parece terriblemente desordenado.

let test (left : Nullable<int>) = if left.HasValue then left.Value else 0 

Console.WriteLine(test (new System.Nullable<int>())) 
Console.WriteLine(test (new Nullable<int>(100))) 

let x = 100 
Console.WriteLine(test (new Nullable<int>(x))) 

Respuesta

17

me temo que no hay azúcar sintáctica para los tipos anulables en F # (a diferencia de C# en el que simplemente añadir una ? con el tipo). Así que sí, el código que muestra parece terriblemente detallado, pero es la única forma de usar el tipo System.Nullable<T> en F #.

Sin embargo, sospecho que lo que realmente quiere utilizar es option types. Hay algunos ejemplos decentes en la página de MSDN:

let keepIfPositive (a : int) = if a > 0 then Some(a) else None 

y

open System.IO 
let openFile filename = 
    try 
     let file = File.Open (filename, FileMode.Create) 
     Some(file) 
    with 
     | exc -> eprintf "An exception occurred with message %s" exc.Message; None 

Claramente mucho más agradable de usar!

Las opciones cumplen esencialmente el rol de los tipos que aceptan nulos en F #, y creo que realmente quieres usarlos en lugar de los tipos que aceptan nulos (a menos que estés haciendo interoperabilidad con C#). La diferencia en la implementación es que los tipos de opciones están formados por una unión discriminada de Some(x) y None, mientras que Nullable<T> es una clase normal en el BCL, con un poco de azúcar sintáctica en C#.

+0

Bien, entonces, ¿cómo convertir un escalar como 100 en una "opción int"? –

+0

El primer ejemplo en mi publicación muestra eso. Para el ejemplo que dio, es simplemente 'Some (100)' – Noldorin

+0

. Ahora hay mucho soporte sintáctico. Ver por ejemplo [todos los operadores que pueden tomar una nullable] (https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/nullable-operators), también como funciones como 'Option.ofNullable',' Option.toNullable' y muchos otros. – Abel

12

Puede dejar que F # inferir la mayor parte de los tipos ahí:

let test (left : _ Nullable) = if left.HasValue then left.Value else 0 

Console.WriteLine(test (Nullable())) 
Console.WriteLine(test (Nullable(100))) 

let x = 100 
Console.WriteLine(test (Nullable(x))) 

También se puede utilizar un active pattern aplicar patrones sobre tipos anulables:

let (|Null|Value|) (x: _ Nullable) = 
    if x.HasValue then Value x.Value else Null 

let test = // this does exactly the same as the 'test' function above 
    function 
    | Value v -> v 
    | _ -> 0 

blogged hace algún tiempo acerca de nullable types in F# [/ shameless_plug]

+0

Acabo de pasar en esto. Puede combinar este enfoque con la serie de Eric Lippert sobre micro optimizaciones con nulos (http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/) y usar 'if n.HasValue then n. GetValueOrDefault() else 0' en su lugar. – phoog

+0

@phoog Siempre que escriba "if n.HasValue" corre el riesgo de escribir una función parcial, por lo que es mejor envolverla en un patrón activo exhaustivo y siempre usarla en su lugar. –

+0

No lo entiendo del todo. ¿Estás diciendo que es mejor * no * definir el patrón activo como 'let (| Null | Value |) (x: _ Nullable) = si x.HasValue luego Value (x.GetValueOrDefault()) else Null'? – phoog