Mit dem Null-Koaleszenz-Operator in c # können Sie den Code verkürzen
if (_mywidget == null)
return new Widget();
else
return _mywidget;
Bis zu:
return _mywidget ?? new Widget();
Ich stelle immer wieder fest, dass ein nützlicher Operator, den ich in C # haben möchte, einer ist, mit dem Sie eine Eigenschaft eines Objekts oder einen anderen Wert zurückgeben können, wenn das Objekt null ist. Also möchte ich ersetzen
if (_mywidget == null)
return 5;
else
return _mywidget.Length;
Mit:
return _mywidget.Length ??! 5;
Ich kann mir nicht helfen zu denken, dass es einen Grund dafür geben muss, dass dieser Operator nicht existiert. Ist es ein Code-Geruch? Gibt es einen besseren Weg, dies zu schreiben? (Ich kenne das Nullobjektmuster, aber es scheint übertrieben, es zu verwenden, um diese vier Codezeilen zu ersetzen.)
c#
code-smell
null
Ben Fulton
quelle
quelle
??!
ist ein Operator in C ++. :-)Antworten:
Ich möchte unbedingt eine C # -Sprachenfunktion, mit der ich x.Prop.SomeOtherProp.ThirdProp sicher ausführen kann, ohne jede dieser Funktionen auf Null prüfen zu müssen. In einer Codebasis, in der ich häufig solche "Deep Property Traversals" durchführen musste, schrieb ich eine Erweiterungsmethode namens Navigate, die NullReferenceExceptions verschluckte und stattdessen einen Standardwert zurückgab. Also könnte ich so etwas machen:
Der Nachteil dabei ist, dass es einen anderen Codegeruch hat: verschluckte Ausnahmen. Wenn Sie so etwas wie "richtig" machen möchten, können Sie die Lamdba als Ausdruck verwenden und den Ausdruck im laufenden Betrieb ändern, um die Nullprüfungen für jeden Eigenschaftszugriff hinzuzufügen. Ich habe mich für "schnell und schmutzig" entschieden und es nicht "besser" umgesetzt. Aber wenn ich ein paar freie Gedankenzyklen habe, werde ich das vielleicht noch einmal überdenken und irgendwo posten.
Um Ihre Frage direkter zu beantworten, schätze ich, dass dies kein Feature ist, weil die Kosten für die Implementierung des Features den Nutzen des Features übersteigen. Das C # -Team muss auswählen, auf welche Funktionen es sich konzentrieren soll, und diese ist noch nicht ganz oben angekommen. Nur eine Vermutung, obwohl ich keine Insider-Informationen habe.
quelle
Ich glaube, Sie können dies jetzt ganz einfach mit C # 6 tun:
Beachten Sie den nullbedingten Operator
?.
auf der linken Seite._mywidget?.Length
Gibt null zurück, wenn_mywidget
null ist.Ein einfacher ternärer Operator ist jedoch möglicherweise leichter zu lesen, wie andere vorgeschlagen haben.
quelle
Es ist wirklich nur eine Spekulation darüber, warum sie es nicht getan haben. Immerhin glaube ich nicht? war in der ersten C # -Version.
Wie auch immer, ich würde einfach den bedingten Operator verwenden und ihn einen Tag nennen:
Das ?? ist nur eine Verknüpfung zum bedingten Operator.
quelle
5
als Antwort an, falls es nicht vorhanden ist. Sie müssen sich Ihr Design ansehen, bevor Sie nach speziellen Operatoren fragen.Es sieht genauso aus wie der ternäre Operator:
quelle
Persönlich denke ich, dass es an der Lesbarkeit liegt. Im ersten Beispiel bedeutet das
??
ganz gut "Bist du da? Nein, lass uns das machen".Im zweiten Beispiel
??!
ist es eindeutig WTF und bedeutet dem Programmierer nichts .... das Objekt existiert nicht, daher kann ich nicht an die Eigenschaft gelangen, also werde ich 5 zurückgeben. Was bedeutet das überhaupt? Was ist 5? Wie kommen wir zu dem Schluss, dass 5 ein guter Wert ist?Kurz gesagt, das erste Beispiel macht Sinn ... nicht da, neu es. Im zweiten ist es offen für Debatten.
quelle
(foo() != ERROR)??!??! cerr << "Error occurred" << endl;
.)5
. Ich denke wirklich, dass es eher ein Problem gibt, dass Sie so etwas tun müssen, während in Ihrem ersten Beispiel die Notwendigkeit ziemlich offensichtlich ist, insbesondere bei Dingen wie Cache-Managern.Ich denke, die Leute sind zu sehr in die "5" verwickelt, als dass Sie zurückkehren ... vielleicht wäre 0 besser gewesen :)
Wie auch immer, ich denke das Problem ist, dass
??!
es sich nicht um einen eigenständigen Operator handelt. Überlegen Sie, was dies bedeuten würde:In diesem Fall macht es keinen Sinn: Es macht nur Sinn, wenn der linke Operand ein Eigenschaftszugriff ist. Oder was ist damit:
Es gibt eine Eigenschaftenaccessor da drin, aber ich glaube immer noch nicht , es Sinn macht (wenn
myWidget
istnull
, heißt das nennen wir nichtFoo()
überhaupt?), Oder ist das nur ein Fehler?Ich denke, das Problem ist, dass es einfach nicht so natürlich in die Sprache
??
passt wie es ist.quelle
Jemand hatte eine Utility-Klasse erstellt, die dies für Sie erledigt. Aber ich kann es nicht finden. Was ich gefunden habe, war etwas Ähnliches in den MSDN-Foren (siehe die zweite Antwort).
Mit ein wenig Arbeit können Sie es erweitern, um Methodenaufrufe und andere Ausdrücke auszuwerten, die das Beispiel nicht unterstützt. Sie können es auch erweitern, um einen Standardwert zu akzeptieren.
quelle
Ich verstehe, woher du kommst. Es scheint, als würden sich alle mit dem von Ihnen angegebenen Beispiel um die Achse wickeln. Ich stimme zwar zu, dass magische Zahlen eine schlechte Idee sind, aber für bestimmte Eigenschaften würde das Äquivalent eines Null-Coallescing-Operators verwendet.
Sie haben beispielsweise Objekte an eine Karte gebunden und möchten, dass sie sich auf der richtigen Höhe befinden. DTED-Karten können Löcher in ihren Daten haben, so dass es möglich ist, einen Nullwert sowie Werte im Bereich von etwa -100 bis ~ 8900 Metern zu haben. Vielleicht möchten Sie etwas in der Art von:
Der Null-Coallescing-Operator würde in diesem Fall die Standardhöhe auffüllen, wenn die Koordinaten noch nicht festgelegt wären oder das Coordinates-Objekt keine DTED-Daten für diesen Speicherort laden könnte.
Ich sehe dies als sehr wertvoll an, aber meine Spekulationen darüber, warum es nicht gemacht wurde, beschränken sich auf die Komplexität des Compilers. Es kann einige Fälle geben, in denen das Verhalten nicht so vorhersehbar ist.
quelle
Wenn ich mich nicht mit tief verschachtelten Operatoren befasse, habe ich dies verwendet (vor dem in C # 6 eingeführten Null-Koaleszenz-Operator). Für mich ist es ziemlich klar, aber vielleicht liegt das daran, dass ich daran gewöhnt bin, andere Leute finden es vielleicht verwirrend.
Dies ist natürlich nicht immer der Fall, da die Eigenschaft, auf die Sie zugreifen müssen, manchmal nicht direkt festgelegt werden kann oder wenn die Konstruktion des Objekts selbst unter anderem teuer ist.
Eine andere Alternative ist die Verwendung des NullObject-Musters . Sie definieren eine einzelne statische Instanz der Klasse mit sinnvollen Standardwerten und verwenden diese stattdessen.
quelle
Magische Zahlen sind normalerweise ein schlechter Geruch. Wenn die 5 eine beliebige Zahl ist, ist es besser, sie so zu formulieren, dass sie klarer dokumentiert ist. Eine Ausnahme wäre meiner Meinung nach, wenn Sie eine Sammlung von Werten haben, die in einem bestimmten Kontext als Standardwerte fungieren.
Wenn Sie eine Reihe von Standardwerten für ein Objekt haben, können Sie diese in Unterklassen unterteilen, um eine Standard-Singleton-Instanz zu erstellen.
So etwas wie: return (myobj ?? default_obj) .Length
quelle
Die Length-Eigenschaft ist normalerweise ein Werttyp, daher kann sie nicht null sein, sodass der Null-Koaleszenz-Operator hier keinen Sinn ergibt.
Sie können dies jedoch mit einer Eigenschaft tun, die ein Referenztyp ist, zum Beispiel:
var window = App.Current.MainWindow ?? new Window();
quelle
Ich habe schon jemanden mit einer ähnlichen Idee gesehen, aber meistens möchten Sie den neuen Wert auch dem Nullfeld zuweisen, etwa:
Die Idee war also, das
??
und die=
Zuordnung zu kombinieren in:Ich denke, das ist sinnvoller als die Verwendung eines Ausrufezeichens.
Diese Idee ist nicht meine, aber ich mag sie wirklich :)
quelle
return _obj ?? new Class();
dass hier keine Notwendigkeit besteht??=
.