Hinweis: Diese Frage vor der Einführung der gebeten wurde , den .?
Operator in C 6 / Visual Studio 2015 , .
Wir waren alle dort, wir haben einige tiefe Eigenschaften wie cake.frosting.berries.loader, die wir überprüfen müssen, ob sie null sind, damit es keine Ausnahme gibt. Der Weg, dies zu tun, besteht darin, eine kurzschließende if-Anweisung zu verwenden
if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...
Dies ist nicht gerade elegant, und es sollte möglicherweise eine einfachere Möglichkeit geben, die gesamte Kette zu überprüfen und festzustellen, ob sie auf eine Nullvariable / -eigenschaft stößt.
Ist es möglich, eine Erweiterungsmethode zu verwenden, oder wäre es eine Sprachfunktion, oder ist es nur eine schlechte Idee?
Antworten:
Wir haben überlegt, eine neue Operation "?" auf die Sprache, die die gewünschte Semantik hat. (Und es wurde jetzt hinzugefügt; siehe unten.) Das heißt, Sie würden sagen
und der Compiler würde alle Kurzschlussprüfungen für Sie generieren.
Es hat die Messlatte für C # 4 nicht erreicht. Vielleicht für eine hypothetische zukünftige Version der Sprache.
Update (2014): Der
?.
Betreiber ist jetzt geplant für die nächste Roslyn Compiler - Release. Beachten Sie, dass es immer noch einige Debatten über die genaue syntaktische und semantische Analyse des Operators gibt.Update (Juli 2015): Visual Studio 2015 wurde veröffentlicht und wird mit einem C # -Compiler geliefert, der die nullbedingten Operatoren
?.
und unterstützt?[]
.quelle
Diese Frage hat mich dazu inspiriert, herauszufinden, wie diese Art der tiefen Nullprüfung mit einer einfacheren / schöneren Syntax unter Verwendung von Ausdrucksbäumen durchgeführt werden kann. Ich stimme zwar den Antworten zu, die besagen, dass dies möglich ist ein schlechtes Design sein , wenn Sie häufig auf Instanzen tief in der Hierarchie zugreifen müssen, aber ich denke auch, dass es in einigen Fällen, wie z. B. bei der Datenpräsentation, sehr nützlich sein kann.
Also habe ich eine Erweiterungsmethode erstellt, mit der Sie schreiben können:
Dies gibt die Beeren zurück, wenn kein Teil des Ausdrucks null ist. Wenn null angetroffen wird, wird null zurückgegeben. Es gibt jedoch einige Einschränkungen: In der aktuellen Version funktioniert es nur mit einfachem Mitgliederzugriff und nur mit .NET Framework 4, da die in Version 4 neue Methode MemberExpression.Update verwendet wird. Dies ist der Code für die IfNotNull-Erweiterungsmethode:
Es funktioniert, indem der Ausdrucksbaum, der Ihren Ausdruck darstellt, untersucht und die Teile nacheinander bewertet werden. jedes Mal, wenn überprüft wird, ob das Ergebnis nicht null ist.
Ich bin sicher, dass dies erweitert werden könnte, so dass andere Ausdrücke als MemberExpression unterstützt werden. Betrachten Sie dies als Proof-of-Concept-Code und denken Sie daran, dass die Verwendung einen Leistungsverlust zur Folge hat (was in vielen Fällen wahrscheinlich keine Rolle spielt, aber nicht in einer engen Schleife verwendet wird :-)).
quelle
DynamicInvoke
dort gesehen. Ich vermeide das religiös :)Ich habe festgestellt, dass diese Erweiterung für Deep-Nesting-Szenarien sehr nützlich ist.
Diese Idee habe ich vom Null-Koaleszenz-Operator in C # und T-SQL abgeleitet. Das Schöne ist, dass der Rückgabetyp immer der Rückgabetyp der inneren Eigenschaft ist.
Auf diese Weise können Sie Folgendes tun:
... oder eine geringfügige Abweichung von den oben genannten:
Es ist nicht die beste Syntax, die ich kenne, aber es funktioniert.
quelle
Abgesehen von der Verletzung des Demeter-Gesetzes, wie Mehrdad Afshari bereits betont hat, scheint es mir, dass Sie für die Entscheidungslogik eine "tiefe Nullprüfung" benötigen.
Dies ist meistens der Fall, wenn Sie leere Objekte durch Standardwerte ersetzen möchten. In diesem Fall sollten Sie das Nullobjektmuster implementieren . Es fungiert als Ersatz für ein reales Objekt und bietet Standardwerte und "Nicht-Aktions" -Methoden.
quelle
Update: Ab Visual Studio 2015 erkennt der C # -Compiler (Sprachversion 6) jetzt den
?.
Operator, was das "Deep Null Checking" zum Kinderspiel macht. Siehe diese Antwort für Details.Abgesehen von der Neugestaltung Ihres Codes, wie in dieser gelöschten Antwort vorgeschlagen, besteht eine andere (wenn auch schreckliche) Option darin, einen
try…catch
Block zu verwenden, um festzustellen, obNullReferenceException
irgendwann während dieser tiefen Eigenschaftssuche ein Fehler auftritt.Ich persönlich würde dies aus folgenden Gründen nicht tun:
NullReferenceException
s sollte wahrscheinlich nie explizit gefangen werden. (Siehe diese Frage .)Dies müsste mit ziemlicher Sicherheit eine Sprachfunktion sein (die in C # 6 in Form von
.?
und?[]
Operatoren verfügbar ist ), es sei denn, C # hatte bereits eine ausgefeiltere verzögerte Auswertung oder Sie möchten Reflektion verwenden (was wahrscheinlich auch keine ist gute Idee aus Gründen der Leistung und Typensicherheit).Da es keine Möglichkeit gibt, einfach
cake.frosting.berries.loader
an eine Funktion zu übergeben (sie würde ausgewertet und eine Nullreferenzausnahme auslösen), müssten Sie eine allgemeine Suchmethode folgendermaßen implementieren: Sie nimmt Objekte und die Namen von Eigenschaften auf Sieh nach oben:(Hinweis: Code bearbeitet.)
Sie sehen schnell mehrere Probleme mit einem solchen Ansatz. Erstens erhalten Sie keine Typensicherheit und kein mögliches Boxen von Eigenschaftswerten eines einfachen Typs. Zweitens können Sie entweder zurückkehren,
null
wenn etwas schief geht, und Sie müssen dies in Ihrer aufrufenden Funktion überprüfen, oder Sie lösen eine Ausnahme aus, und Sie kehren zu Ihrem Ausgangspunkt zurück. Drittens könnte es langsam sein. Viertens sieht es hässlicher aus als das, womit Sie begonnen haben.Ich würde entweder bleiben bei:
oder gehen Sie mit der obigen Antwort von Mehrdad Afshari.
PS: Als ich diese Antwort schrieb, habe ich offensichtlich keine Ausdrucksbäume für Lambda-Funktionen berücksichtigt. Siehe zB die Antwort von @driis für eine Lösung in dieser Richtung. Es basiert auch auf einer Art Reflexion und ist daher möglicherweise nicht ganz so gut wie eine einfachere Lösung (
if (… != null & … != null) …
), kann jedoch aus syntaktischer Sicht besser beurteilt werden.quelle
Die Antwort von driis ist zwar interessant, aber meiner Meinung nach in Bezug auf die Leistung etwas zu teuer. Anstatt viele Delegaten zu kompilieren, würde ich es vorziehen, ein Lambda pro Eigenschaftspfad zu kompilieren, es zwischenzuspeichern und dann viele Typen neu aufzurufen.
NullCoalesce unten macht genau das. Es gibt einen neuen Lambda-Ausdruck mit Nullprüfungen und einer Standardrückgabe (TResult) zurück, falls ein Pfad null ist.
Beispiel:
Gibt einen Ausdruck zurück
Code:
quelle
Eine Möglichkeit besteht darin, das Null-Objekt-Patten zu verwenden. Statt Null zu haben, wenn Sie keinen Kuchen haben, haben Sie einen Null-Kuchen, der ein NullFosting usw. zurückgibt. Tut mir leid, ich kann das nicht sehr gut erklären, aber andere Leute sind es, siehe
quelle
Auch ich habe mir oft eine einfachere Syntax gewünscht! Es wird besonders hässlich, wenn Sie Methodenrückgabewerte haben, die möglicherweise null sind, weil Sie dann zusätzliche Variablen benötigen (zum Beispiel:
cake.frosting.flavors.FirstOrDefault().loader
)Hier ist jedoch eine ziemlich anständige Alternative, die ich verwende: Erstellen Sie eine Null-Safe-Chain-Hilfsmethode. Mir ist klar, dass dies der obigen Antwort von @ John (mit der
Coal
Erweiterungsmethode) ziemlich ähnlich ist, aber ich finde, dass es einfacher ist und weniger tippt. So sieht es aus:Hier ist die Implementierung:
Ich habe auch mehrere Überladungen (mit 2 bis 6 Parametern) sowie Überladungen erstellt, die es der Kette ermöglichen, mit einem Werttyp oder einer Standardeinstellung zu enden. Das funktioniert wirklich gut für mich!
quelle
Es gibt ein Vielleicht-Codeplex-Projekt , das Vielleicht oder IfNotNull implementiert und Lambdas für tiefe Ausdrücke in C # verwendet
Anwendungsbeispiel:
Der Link wurde in einer ähnlichen Frage vorgeschlagen. Wie wird in einem tiefen Lambda-Ausdruck nach Nullen gesucht?
quelle
Wie in der Antwort von John Leidegren vorgeschlagen , besteht ein Ansatz zur Umgehung dieses Problems darin , Erweiterungsmethoden und Delegaten zu verwenden. Ihre Verwendung könnte ungefähr so aussehen:
Die Implementierung ist unübersichtlich, da sie für Werttypen, Referenztypen und nullfähige Werttypen funktionieren muss. Sie können eine vollständige Implementierung in finden Timwi ‚s Antwort auf Was ist der richtige Weg ist für Null - Werte zu überprüfen? .
quelle
Oder Sie können Reflexion verwenden :)
Reflexionsfunktion:
Verwendung:
Mein Fall (DBNull.Value anstelle von null in der Reflexionsfunktion zurückgeben):
quelle
Versuchen Sie diesen Code:
quelle
Ich habe das letzte Nacht gepostet und dann hat mich ein Freund auf diese Frage hingewiesen. Ich hoffe es hilft. Sie können dann so etwas tun:
Lesen Sie hier den vollständigen Blog-Beitrag .
Der gleiche Freund schlug auch vor, dass Sie dies sehen .
quelle
Expression
wenn Sie nur kompilieren und fangen wollen? Verwenden Sie einfach eineFunc<T>
.Ich habe den Code von hier aus leicht geändert , damit er für die gestellte Frage funktioniert:
Und ja, dies ist wahrscheinlich nicht die optimale Lösung, da die Leistung beeinträchtigt wird, aber es funktioniert:>
Verwendung:
quelle
Wo Sie dies erreichen müssen, tun Sie Folgendes:
Verwendung
oder
Implementierung der Hilfsklasse
quelle
Ich mag den Ansatz von Objective-C:
"Die Objective-C-Sprache verfolgt einen anderen Ansatz für dieses Problem und ruft keine Methoden für nil auf, sondern gibt für alle derartigen Aufrufe nil zurück."
quelle