W .NET istnieją dwie kategorie typów: odwołania i wartości (int, double, structs, enums itp.). Wśród ich różnic jest fakt, że referencja może być null
, podczas gdy wartość nie. Zatem jeśli masz typ wartości i chcesz przekazać „opcjonalną” lub „nieznaną” semantykę, możesz ją ozdobić Nullable<>
. Zauważ, że Nullable<>
jest ograniczony przez typ, aby akceptować tylko typy wartości (ma where T : struct
klauzulę). Nullable<>
ma również specjalne afordancje od kompilatora, dzięki którym null
wartość jest chroniona przed NullReferenceExceptions
:
string x = null;
x.ToString(); // throws a NullReferenceException
int? y = null;
y.ToString(); // returns ""
W językach funkcjonalnych (takich jak Scala, F #, Haskell, Swift itp) to jest wspólne dla null
celu nie istnieje . Jest tak, ponieważ ogólnie ludzie uważają istnienie tego null
za zły pomysł , a projektanci języków postanowili rozwiązać ten problem, nie pozwalając mu na to.
Oznacza to, że ponownie potrzebujemy jakiegoś sposobu przedstawienia nie-wartości w tych językach. Wpisz Option
typ (nomenklatura jest różna, nazywa się Maybe
w Haskell). Wykonuje to podobne zadanie Nullable
, ponieważ otacza typ, aby dodać przypadek, w którym wartość to „Brak” lub „Nieznany” itp.
Prawdziwa różnica polega na tym, że dodatkowe funkcje są dostępne w implementowanych językach Option
. Jako przykład weź Option.map
(w pseudokodzie):
function Option<T2> Option.map(opt: Option<T1>, mapFunc: T1 -> T2) {
if (opt is None) return None
else return Option<T2>(mapFunc(opt.Value))
}
Łańcuchowe funkcje, takie jak, Option.map
to potężny sposób na uniknięcie typowej płyty kontrolnej zerowania, którą widzisz wszędzie w C #:
if (service == null)
return null;
var x = service.GetValue();
if (x == null || x.Property == null)
return null;
return x.Property.Value;
Nullable równoważne w C # byłoby:
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);
}
Jednak ma to ograniczoną użyteczność w języku C #, ponieważ będzie działać tylko dla typów wartości.
Nowa wersja C # oferuje operator „zerowej propagacji” ( ?.
), który jest podobny do Option.map
funkcji, z tą różnicą, że ma zastosowanie tylko do metod i akcesorów właściwości. Powyższa próbka zostanie przepisana
return service?.GetValue()?.Property?.Value;