In .NET, ci sono due categorie di tipi: riferimenti e valori (int, double, structs, enum ecc.). Tra le loro differenze c'è il fatto che un riferimento può essere null
, mentre un valore non può. Quindi se hai un tipo di valore e vuoi trasmettere una semantica "opzionale" o "sconosciuta", puoi adornarla con Nullable<>
. Nota che Nullable<>
è vincolato dal tipo per accettare solo i tipi di valore (ha una clausola where T : struct
). Nullable<>
ha anche accessi speciali dal compilatore per cui un valore null
è protetto da NullReferenceExceptions
:
string x = null;
x.ToString(); // throws a NullReferenceException
int? y = null;
y.ToString(); // returns ""
Nei linguaggi funzionali (come Scala, F #, Haskell, Swift ecc.) è comune per null
a non esiste . Questo perché nel complesso le persone considerano l'esistenza di null
come un cattiva idea , e i progettisti di linguaggi hanno deciso di risolvere questo problema disabilitandolo.
Ciò significa che ancora una volta abbiamo bisogno di un modo per rappresentare un non-valore in queste lingue. Inserisci il tipo Option
(la nomenclatura varia, è chiamata Maybe
in Haskell). Questo fa un lavoro simile a Nullable
in quanto avvolge un tipo per aggiungere il caso in cui il valore è "Nessuno" o "Sconosciuto" ecc.
La vera differenza è nelle funzioni extra fornite da lingue che implementano Option
. Ad esempio, prendi Option.map
(in pseudocodice):
function Option<T2> Option.map(opt: Option<T1>, mapFunc: T1 -> T2) {
if (opt is None) return None
else return Option<T2>(mapFunc(opt.Value))
}
Il concatenamento funziona come Option.map
è un modo efficace per evitare il tipico tagliando di controllo nullo che vedi ovunque in C #:
if (service == null)
return null;
var x = service.GetValue();
if (x == null || x.Property == null)
return null;
return x.Property.Value;
L'equivalente Nullable in C # sarebbe:
public static Nullable<T2> Map<T1, T2>(this Nullable<T1> nullable, Func<T1, T2> f)
where T1 : struct
where T2 : struct
{
if (!nullable.HasValue) return (T2?)null;
else return (T2?) f(nullable.Value);
}
Tuttavia questo ha un'utilità limitata in C # perché funzionerà solo con i tipi di valore.
La nuova versione di C # offre l'operatore "propagazione nulla" ( ?.
) che è simile alla funzione Option.map
, eccetto che è applicabile solo per metodi e accessi di proprietà. L'esempio precedente verrebbe riscritto
return service?.GetValue()?.Property?.Value;