In .NET gibt es zwei Kategorien von Typen: Referenzen und Werte (int, double, structs, enums usw.). Zu ihren Unterschieden gehört die Tatsache, dass eine Referenz sein kann null
, während ein Wert dies nicht kann. Wenn Sie also einen Wertetyp haben und "optionale" oder "unbekannte" Semantik übermitteln möchten, können Sie ihn mit schmücken Nullable<>
. Beachten Sie, dass Nullable<>
typabhängig nur Werttypen zulässig sind (es gibt eine where T : struct
Klausel). Nullable<>
hat auch spezielle Vergünstigungen vom Compiler, wodurch ein null
Wert geschützt ist vor NullReferenceExceptions
:
string x = null;
x.ToString(); // throws a NullReferenceException
int? y = null;
y.ToString(); // returns ""
In funktionalen Sprachen (wie Scala, F #, Haskell, Swift usw.) ist es üblich, dass null
sie nicht existieren . Dies liegt daran, dass die Existenz von im Großen und Ganzen null
als eine schlechte Idee angesehen wird und die Sprachdesigner beschlossen haben, dieses Problem zu lösen, indem sie es nicht zulassen.
Dies bedeutet, dass wir in diesen Sprachen wieder eine Möglichkeit benötigen, einen Nicht-Wert darzustellen . Geben Sie den Option
Typ ein (die Nomenklatur variiert, Maybe
in Haskell heißt sie). Dies ist insofern ähnlich Nullable
, als es einen Typ umschließt, um den Fall hinzuzufügen, in dem der Wert "Keine" oder "Unbekannt" usw. ist.
Der wahre Unterschied liegt in den zusätzlichen Funktionen, die Ihnen von den implementierten Sprachen zur Verfügung gestellt werden Option
. Nehmen Sie als Beispiel Option.map
(in Pseudocode):
function Option<T2> Option.map(opt: Option<T1>, mapFunc: T1 -> T2) {
if (opt is None) return None
else return Option<T2>(mapFunc(opt.Value))
}
Verkettungsfunktionen wie Option.map
sind eine leistungsstarke Methode, um das typische Null-Check-Boilerplate zu vermeiden, das Sie überall in C # sehen:
if (service == null)
return null;
var x = service.GetValue();
if (x == null || x.Property == null)
return null;
return x.Property.Value;
Das Nullable-Äquivalent in C # wäre:
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);
}
Dies ist jedoch in C # nur eingeschränkt nützlich, da es nur für Werttypen funktioniert.
Die neue Version von C # bietet den Operator "Null-Propagation" ( ?.
), der der Option.map
Funktion ähnlich ist, außer dass er nur für Methoden und Eigenschafts-Accessoren gilt. Das obige Beispiel würde neu geschrieben
return service?.GetValue()?.Property?.Value;