Wenn Sie eine Erweiterungsmethode erstellen können Sie, natürlich, nennen es auf null
.Aber, im Gegensatz zu einer Instanz Methodenaufruf, es auf null Aufruf nicht haben eine werfen NullReferenceException
-> müssen Sie prüfen , und es manuell zu werfen.
Für die Implementierung der Linq-Erweiterungsmethode hat Any()
Microsoft entschieden, dass ein ArgumentNullException
( https://github.com/dotnet/corefx/blob/master/src/System.Linq/src/System/Linq/AnyAll.cs ) ausgelöst werden soll .
Es nervt mich zu schreiben if( myCollection != null && myCollection.Any() )
Bin ich falsch, als Client dieses Codes zu erwarten, dass zB zurückkehren ((int[])null).Any()
sollte false
?
c#
.net
linq
extension-method
dies verlängertdass
quelle
quelle
null |> Seq.isEmpty
führtSystem.ArgumentNullException: Value cannot be null
. Die Erwartung scheint zu sein, dass Sie keine undefinierten Werte für etwas übergeben, von dem erwartet wird, dass es existiert. Es ist also immer noch eine Ausnahme, wenn Sie eine Null haben. Wenn es um die Initialisierung geht, würde ich mit einer leeren Sequenz anstelle von a beginnennull
.null
beim Umgang mit Sammlungen nicht zurückkehren , sondern in diesen Fällen eine leere Sammlung verwenden.Any
ist nur konsequent.Antworten:
Ich habe eine Tüte mit fünf Kartoffeln drin. Befinden sich
.Any()
Kartoffeln in der Tüte?" Ja ", sagst du.
<= true
Ich nehme alle Kartoffeln heraus und esse sie. Befinden sich
.Any()
Kartoffeln in der Tüte?" Nein ", sagst du.
<= false
Ich verbrenne die Tüte komplett im Feuer. Sind
.Any()
jetzt Kartoffeln in der Tüte?" Es gibt keine Tasche ."
<= ArgumentNullException
quelle
Zunächst scheint es, dass der Quellcode nicht werfen
ArgumentNullException
wirdNullReferenceException
.In vielen Fällen wissen Sie jedoch bereits, dass Ihre Sammlung nicht null ist, da dieser Code nur von Code aufgerufen wird, der weiß, dass die Sammlung bereits vorhanden ist, sodass Sie den Null-Check dort nicht sehr oft eingeben müssen. Aber wenn Sie nicht wissen, dass es existiert, ist es sinnvoll, dies zu überprüfen, bevor Sie es aufrufen
Any()
.Ja. Die Frage
Any()
lautet: "Enthält diese Sammlung Elemente?" Wenn diese Sammlung nicht existiert, ist die Frage selbst unsinnig; es kann nichts enthalten oder nicht enthalten, weil es nicht existiert.quelle
null
entspricht, die die leere Menge enthält (und umgekehrt)?{ null }
und{ {} }
sollten gleichwertig sein. Das finde ich faszinierend; Ich kann überhaupt nichts damit anfangen..Add
aufnull
irgendeine Weise eine Sammlung auch für uns erstellt werden?Null bedeutet fehlende Informationen, keine Elemente.
Möglicherweise sollten Sie Null allgemein vermeiden. Verwenden Sie beispielsweise eine der integrierten leeren Enumerables, um eine Auflistung ohne Elemente anstelle von Null darzustellen.
Wenn Sie unter bestimmten Umständen null zurückgeben, können Sie dies ändern, um die leere Auflistung zurückzugeben. (Andernfalls ist es bedauerlich, wenn Sie feststellen, dass Nullen von Bibliotheksmethoden zurückgegeben werden (nicht von Ihren), und ich würde sie zur Normalisierung einpacken.)
Siehe auch https://stackoverflow.com/questions/1191919/what-does-linq-return-when-the-results-are-empty
quelle
null
heißt nicht, dass keine Elemente eine sinnvolle Konvention sind. Denken Sie nur an native OLESTRINGS, wo das eigentlich heißt .null
es nicht "fehlende Informationen" bedeutet.null
hat keine einzige sinnvolle Interpretation. Stattdessen geht es darum, wie Sie damit umgehen.null
wird manchmal für "fehlende Informationen", aber auch für "keine Elemente" und auch für "ein Fehler ist aufgetreten" oder "nicht initialisiert" oder "widersprüchliche Informationen" oder eine beliebige, ad-hoc-Sache verwendet.null
wird absolut häufig verwendet, um "keine Daten" zu bedeuten. Manchmal macht es Sinn. Andere Male nicht.Abgesehen von der nullbedingten Syntax gibt es eine andere Technik, um dieses Problem zu beheben: Lassen Sie Ihre Variable niemals übrig
null
.Stellen Sie sich eine Funktion vor, die eine Auflistung als Parameter akzeptiert. Wenn für die Zwecke der Funktion
null
und leer gleichwertig sind, können Sie sicherstellen, dass esnull
zu Beginn nie enthält :Sie können dasselbe tun, wenn Sie Sammlungen von einer anderen Methode abrufen:
(Beachten Sie, dass in Fällen , in denen Sie die Kontrolle über eine Funktion haben , wie
GetWords
undnull
entsprechen die leere Sammlung, es vorzuziehen ist , zurückzukehren nur die leere Sammlung an erster Stelle.)Jetzt können Sie jede gewünschte Operation für die Sammlung ausführen. Dies ist besonders hilfreich, wenn Sie viele Vorgänge ausführen müssen, bei denen die Auflistung fehlschlagen würde
null
, und in Fällen, in denen Sie das gleiche Ergebnis erhalten, indem Sie eine leere Aufzählung durchlaufen oder abfragen, können Sie dieif
Bedingungen vollständig entfernen.quelle
Ja, einfach, weil Sie in C # arbeiten und dieses Verhalten gut definiert und dokumentiert ist.
Wenn Sie eine eigene Bibliothek erstellen oder eine andere Sprache mit einer anderen Ausnahmekultur verwenden, ist es vernünftiger, mit false zu rechnen.
Persönlich denke ich, dass return false ein sicherer Ansatz ist, der Ihr Programm robuster macht, aber zumindest umstritten ist.
quelle
Wenn Sie die wiederholten Nullprüfungen stören, können Sie Ihre eigene Erweiterungsmethode 'IsNullOrEmpty ()' erstellen, um die String-Methode mit diesem Namen zu spiegeln, und sowohl die Nullprüfung als auch den Aufruf von .Any () in einen einzigen Aufruf umbrechen.
Ansonsten ist die Lösung, die von @ 17 von 26 in einem Kommentar unter Ihrer Frage erwähnt wird, ebenfalls kürzer als die 'Standard'-Methode und für jeden, der mit der neuen nullbedingten Syntax vertraut ist, einigermaßen klar.
quelle
?? false
anstelle von verwenden== true
. Dies scheint mir eindeutiger (klarer) zu sein, da es nur den Fall von behandeltnull
und nicht wirklich ausführlicher ist. Plus-==
Checks auf Boolesche Werte lösen normalerweise meinen Würgereflex aus. =)myCollection?.Any()
genug?myCollection?.Any()
effektiv ein nullable-Boolean anstelle eines gewöhnlichen Boolean (dh bool? Anstelle von bool) zurückgegeben. Es gibt keine implizite Konvertierung von Bool? zu boolen, und es ist ein Bool, den wir in diesem speziellen Beispiel brauchen (um als Teil derif
Bedingung zu testen ). Daher müssen wir entweder explizit mittrue
dem Null-Koaleszenz-Operator (??) vergleichen oder diesen verwenden.?.
.==
es tatsächlich funktionieren wird. Ich weiß schon intuitiv, was mit einem Booleschen passiert, wenn es nur sein kanntrue
oderfalse
; Ich muss nicht einmal darüber nachdenken. Aber reinnull
in die Mischung, und jetzt muss ich herausfinden, ob das==
richtig ist.??
Stattdessen wird nur dernull
Fall beseitigttrue
und auf und reduziertfalse
, was Sie bereits sofort verstehen. Wenn ich meinen Würgereflex zum ersten Mal sehe, besteht mein unmittelbarer Instinkt darin, ihn einfach zu löschen, da er normalerweise unbrauchbar ist, was Sie nicht wollen.Wenn Sie sich über Erwartungen wundern, müssen Sie über Absichten nachdenken.
null
bedeutet etwas ganz anderes alsEnumerable.Empty<T>
Wie in Erik Eidts Antwort erwähnt , gibt es einen Bedeutungsunterschied zwischen
null
und einer leeren Sammlung.Schauen wir uns zunächst an, wie sie verwendet werden sollen.
In dem von den Microsoft-Architekten Krzysztof Cwalina und Brad Abrams verfassten Buch Framework Design Guidelines: Konventionen, Redewendungen und Muster für wiederverwendbare .NET-Bibliotheken (2. Auflage) wird die folgende bewährte Methode angegeben:
Stellen Sie sich vor, Sie rufen eine Methode auf, die letztendlich Daten aus einer Datenbank abruft: Wenn Sie ein leeres Array erhalten oder
Enumerable.Empty<T>
dies einfach bedeutet, dass Ihr Probenraum leer ist, dh Ihr Ergebnis ist eine leere Menge . Empfangennull
in diesem Zusammenhang würde jedoch einen Fehlerzustand bedeuten .Entsprechend der Kartoffel-Analogie von Dan Wilson ist es sinnvoll, Fragen zu Ihren Daten zu stellen, auch wenn es sich um eine leere Menge handelt . Aber es macht viel weniger Sinn, wenn es keinen Satz gibt .
quelle
null
und leer kann zu demselben Rückgabewert für die Funktion führen, aber das bedeutet nicht, dassnull
und leer genau dasselbe im aufrufenden Bereich bedeuten.Es gibt viele Antworten, die erklären, warum
null
und leer unterschiedlich sind, und genug Meinungen, die versuchen , beide zu erklären, warum sie unterschiedlich behandelt werden sollten oder nicht. Sie fragen jedoch:Es ist eine völlig vernünftige Erwartung . Sie haben genauso recht wie jemand anderer, der sich für das aktuelle Verhalten einsetzt. Ich stimme der aktuellen Implementierungsphilosophie zu, aber die treibenden Faktoren beruhen nicht nur auf kontextunabhängigen Überlegungen.
Vorausgesetzt, dass
Any()
ohne Prädikat im WesentlichenCount() > 0
ist, was erwarten Sie dann von diesem Snippet?Oder ein Generikum:
Ich nehme an, Sie erwarten
NullReferenceException
.Any()
Wenn es sich um eine Erweiterungsmethode handelt, die sich nahtlos in das erweiterte Objekt integrieren lässt, ist es am wenigsten überraschend, eine Ausnahme auszulösen.Enumerable.Any(null)
und dort erwarten Sie auf jeden FallArgumentNullException
. Es ist die gleiche Methode und muss mit - möglicherweise - ALLEN anderen im Framework übereinstimmen.null
Objekt ist ein Programmierfehler . Das Framework sollte Null nicht als magischen Wert erzwingen . Wenn Sie es so verwenden, liegt es in Ihrer Verantwortung, damit umzugehen.Count()
treffenWhere()
. Wenn eine einfache Entscheidung zu sein scheint, ist dies nicht der Fall . Was istMax()
? Es löst eine Ausnahme für eine leere Liste aus, sollte es nicht auch für eine eine auslösennull
?Was Bibliotheksdesigner vor LINQ taten, war, explizite Methoden einzuführen, wenn
null
ein gültiger Wert (zum BeispielString.IsNullOrEmpty()
) vorliegt, dann MÜSSEN sie mit der vorhandenen Designphilosophie übereinstimmen . Das heißt, wenn auch ziemlich trivial zu schreiben, zwei MethodenEmptyIfNull()
undEmptyOrNull()
könnte praktisch sein.quelle
Jim soll Kartoffeln in jeder Tüte lassen. Sonst werde ich ihn töten.
Jim hat eine Tüte mit fünf Kartoffeln drin. Befinden sich
.Any()
Kartoffeln in der Tüte?"Ja", sagst du. <= wahr
Ok, Jim lebt dieses Mal.
Jim nimmt alle Kartoffeln heraus und isst sie. Befinden sich Kartoffeln in der Tüte?
"Nein", sagst du. <= false
Zeit Jim zu töten.
Jim verbrennt die Tüte komplett im Feuer. Befindet sich jetzt eine () Kartoffel in der Tüte?
"Es gibt keine Tasche." <= ArgumentNullException
Sollte Jim leben oder sterben? Nun, wir haben das nicht erwartet, also brauche ich ein Urteil. Ist es ein Fehler, Jim damit davonkommen zu lassen oder nicht?
Sie können Anmerkungen verwenden, um zu signalisieren, dass Sie auf diese Weise keine Null-Spielereien ertragen.
Aber Ihre Werkzeugkette muss es unterstützen. Das bedeutet, dass Sie wahrscheinlich trotzdem Schecks schreiben werden.
quelle
Wenn Sie das so sehr stört, schlage ich eine einfache Erweiterungsmethode vor.
Jetzt können Sie dies tun:
... und das Flag wird auf gesetzt
false
.quelle
return
Aussage wiereturn source ?? Enumerable.Empty<T>();
Dies ist eine Frage zu den Erweiterungsmethoden von C # und ihrer Entwurfsphilosophie. Ich denke, die beste Möglichkeit, diese Frage zu beantworten, besteht darin, die Dokumentation von MSDN zum Zweck der Erweiterungsmethoden zu zitieren :
Zusammenfassend lässt sich sagen, dass Erweiterungsmethoden so konzipiert sind, dass sie einem bestimmten Typ Instanzmethoden hinzufügen, auch wenn die Entwickler dies nicht direkt können. Und da Instanzmethoden Erweiterungsmethoden immer überschreiben, wenn sie vorhanden sind (wenn sie mithilfe der Instanzmethodensyntax aufgerufen werden), sollte dies nur erfolgen, wenn Sie keine Methode direkt hinzufügen oder die Klasse erweitern können. *
Mit anderen Worten, eine Erweiterungsmethode sollte genau wie eine Instanzmethode funktionieren, da sie möglicherweise von einem Client zu einer Instanzmethode gemacht wird. Und weil eine Instanzmethode werfen sollte, wenn das Objekt, für das sie aufgerufen wird
null
, ist , sollte dies auch die Erweiterungsmethode tun.* Als Randbemerkung ist dies genau die Situation, mit der die Designer von LINQ konfrontiert waren: Als C # 3.0 veröffentlicht wurde, gab es bereits Millionen von Clients, die
System.Collections.IEnumerable
und verwendetenSystem.Collections.Generic.IEnumerable<T>
, sowohl in ihren Sammlungen als auch inforeach
Schleifen. Diese Klassen zurückIEnumerator
Objekte , die nur hatten die beiden MethodenCurrent
undMoveNext
, so das Hinzufügen alle zusätzliche erforderliche Instanzmethoden, wie zum BeispielCount
,Any
usw., würde diese Millionen von Kunden brechen. Also, um diese Funktionalität bereitzustellen (vor allem , da es in Bezug auf die umgesetzt werden könnenCurrent
undMoveNext
mit relativer Leichtigkeit), veröffentlichten sie es als Erweiterungsmethoden, die auf jede derzeit angewendet werden , können bestehendeIEnumerable
Instanz und kann auch von Klassen auf effizientere Weise implementiert werden. Hätten die Entwickler von C # beschlossen, LINQ am ersten Tag freizugeben, wäre es als Instanzmethode von bereitgestellt wordenIEnumerable
, und sie hätten wahrscheinlich eine Art System entworfen, das Standardschnittstellenimplementierungen dieser Methoden bereitstellt.quelle
Ich denke, der springende Punkt hier ist, dass Sie durch das Zurückgeben von false anstelle des Auslösens einer Ausnahme Informationen verschleiern, die für zukünftige Leser / Modifikatoren Ihres Codes relevant sein könnten.
Wenn es möglich ist, dass die Liste null ist, würde ich vorschlagen, einen separaten Logikpfad dafür zu haben, da ansonsten in Zukunft jemand eine listenbasierte Logik (wie ein Add) zum else {} Ihres if hinzufügen könnte, was zu einem führt ungewollte Ausnahme, dass sie keinen Grund hatten, vorherzusagen.
Lesbarkeit und Wartbarkeit sind die Trümpfe, dass ich jedes Mal eine zusätzliche Bedingung schreiben muss.
quelle
Im Allgemeinen schreibe ich den größten Teil meines Codes, um anzunehmen, dass der Anrufer dafür verantwortlich ist, mir keine Nulldaten zu übergeben, und zwar hauptsächlich aus den in „ Nein zu Null sagen“ (und anderen ähnlichen Beiträgen) genannten Gründen . Das Konzept von Null ist oft nicht gut verstanden, und aus diesem Grund ist es ratsam, Ihre Variablen so früh wie möglich zu initialisieren. Angenommen, Sie arbeiten mit einer vernünftigen API, sollten Sie im Idealfall niemals einen Nullwert zurückerhalten, sodass Sie niemals nach Null suchen müssen. Der Nullpunkt ist, wie in anderen Antworten angegeben, sicherzustellen, dass Sie ein gültiges Objekt (z. B. eine "Tasche") haben, mit dem Sie arbeiten können, bevor Sie fortfahren. Dies ist kein Merkmal von
Any
, sondern ein Merkmal der Spracheselbst. Sie können die meisten Vorgänge für ein Nullobjekt nicht ausführen, da es nicht vorhanden ist. Es ist so, als würde ich Sie bitten, in meinem Auto zum Geschäft zu fahren, außer ich besitze kein Auto, also haben Sie keine Möglichkeit, mit meinem Auto zum Geschäft zu fahren. Es ist unsinnig, eine Operation an etwas durchzuführen, das buchstäblich nicht existiert.Es gibt praktische Fälle für die Verwendung von null, z. B. wenn Sie buchstäblich nicht über die angeforderten Informationen verfügen (z. B. wenn ich Sie nach meinem Alter gefragt habe, lautet die wahrscheinlichste Antwort an dieser Stelle "Ich weiß nicht" ", was ein Nullwert ist). In den meisten Fällen sollten Sie jedoch zumindest wissen, ob Ihre Variablen initialisiert sind oder nicht. Und wenn nicht, dann würde ich empfehlen, dass Sie Ihren Code verschärfen müssen. Das allererste, was ich in einem Programm oder einer Funktion mache, ist, einen Wert zu initialisieren, bevor ich ihn benutze. Es ist selten, dass ich nach Nullwerten suchen muss, da ich garantieren kann, dass meine Variablen nicht Null sind. Es ist eine gute Angewohnheit, sich darauf einzulassen, und je häufiger Sie daran denken, Ihre Variablen zu initialisieren, desto seltener müssen Sie nach null suchen.
quelle