Wie weit sollten 'var' und Null-Koaleszenzoperator '??' unterhalten werden, ohne die Lesbarkeit zu beeinträchtigen?

23

Ich weiß, dass der Titel der Frage sehr subjektiv ist, aber ich wurde ??von meinen Kollegen mit der Verwendung von Operatoren konfrontiert , wobei ich gleichzeitig nicht sehr zufrieden mit der Anwendung varvon neuem Code war.

Das Argument für die Verwendung von ??operator war, dass es die Lesbarkeit im Code beeinträchtigt.

Meine Frage ist, passiert nicht dasselbe, wenn Sie anfangen zu benutzen var?

Numan
quelle
49
Wenn ein "Entwickler" den ??Null-Coalesce-Operator nicht verstehen kann, nachdem er erklärt wurde, sollte er nicht in der Nähe von Produktionscode zugelassen werden.
CaffGeek
12
Ich schlage vor, wir ändern den Operator von ?? zu IfNullThen. ? kann IfSoChoose sein,: ist ElseChoose. + ist Hinzufügen. - ist subtrahieren, es sei denn, es ist unär, dann ist es negativ. - wird zwischen DecrementBeforeUsing und DecrementAfterUsing aufgeteilt. In C ++ können Sie dies mit Makros tun.
Lee Louviere
7
@Xaade: Das ist Ironie, nicht wahr? ... Recht? ... Gott lass es Ironie sein (und ich bin ein Atheist).
Steven Jeuris
10
@StevenJeuris Es mag Sarkasmus sein , aber es ist keine Ironie .
Kirk Broadhurst
1
@KirkBroadhurst: Ich stehe korrigiert da , habe diese beiden immer verwechselt.
Steven Jeuris

Antworten:

53

Null-Koaleszenzoperator (??)

Persönlich sehe ich keine Nachteile bei der Verwendung dieses Operators. Betrachten Sie die folgenden drei Codebeispiele, von "einfachen" bis "komplexen" neuen Operatoren.

Ohne Magie:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Ternärer Operator:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Null-Koaleszenz:

string name = null;
Console.WriteLine( name ?? "No name set." );

Der Grund, warum diese Operatoren erfunden wurden, ist, dass sie sehr häufige Programmiervorgänge darstellen . Sie nicht benutzen zu wollen, weil Sie nicht an sie gewöhnt sind, ist nur hartnäckig . Sprachen entwickeln sich, Funktionen entwickeln sich, lernen, sie zu benutzen!

var Schlüsselwort

Ich habe eine etwas andere Meinung über das Schlüsselwort var. Der Typ einer Variablen enthält häufig zusätzliche Informationen zu Ihrem Code. Wenn ich den Typ mit dem Schlüsselwort var verstecke, ist der Code manchmal weniger lesbar. Sie wissen weniger, was Sie erwarten können, wenn Sie die automatische Vervollständigung nicht verwenden oder den Mauszeiger über die Bezeichner halten, um zu sehen, was diese tatsächlich sind. Meiner Meinung nach führt dies zu Code, der langsamer zu lesen / schreiben ist.

Ich verwende das Schlüsselwort, wenn ich feststelle, dass der Typ nicht viele zusätzliche Informationen enthält.

  • Hauptsächlich in foreach-Schleifen , die ich von Resharper gelernt habe, da es sich um eine Einstellung handelt. In den meisten Fällen wissen Sie, welche Art von Sammlung Sie gerade durchlaufen, sodass Sie wissen, dass Sie Elemente aus dieser Sammlung erwarten.
  • Linq-Abfragen . Das Ergebnis von Linq-Abfragen sind oft sehr komplexe generische Typen. Das Anzeigen dieses Typs schadet mehr als es nützt.
  • Lange Typnamen, die einfach mit ihrem Konstruktor initialisiert werden. Anhand des Konstruktors können Sie bereits erkennen, um welchen Typ es sich handelt.

Als Beispiel für die letzte Aussage:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();
Steven Jeuris
quelle
24
Das letzte Beispiel ist genau dann, wenn das Schlüsselwort var eine hervorragende Leistung erbringen kann. Stellen Sie sich vor, der Code ist in Ihrem gesamten Code verstreut. Factory.CreateSomeTypekehrt zurück IEnumerable<SomeType>. Eines Tages, aus welchem ​​Grund auch immer, ändert es sich, um zurückzukehren SomeType[]. Wenn Sie var verwendet haben, handelt es sich nur um eine Neukompilierung.
pdr
1
Ich habe das Beispiel falsch verstanden und bin dann losgegangen, um Essen zu suchen. Numpty! Ein besseres Beispiel wäre Ihre. Was passiert, wenn Factory.CreateSomeType()Änderungen zurückgegeben werden ISomeType?
pdr
4
@pdr: Das bedeutet höchstwahrscheinlich, dass sich auch die Benutzeroberfläche geändert hat und das Verhalten angepasst / hinzugefügt werden muss. Wenn es sich um eine einfache Umbenennung handelt, haben Sie natürlich eine automatische Umbenennung. Wenn sich der 'Vertrag' ändert, sehe ich eher, dass mein Code kaputt geht, damit ich sehen kann, ob ich etwas anpassen muss oder nicht.
Steven Jeuris
2
Ich denke, es ist viel wahrscheinlicher, dass bei der Rückgabe eines konkreten Typs eine Schnittstelle zurückgegeben wird, die nur andere konkrete Typen mit derselben Schnittstelle zulässt (im Einklang mit dem Factory-Muster). Aber wenn sich der Vertrag ändert, bricht Ihr Code - obwohl Sie ihn möglicherweise nur in wenigen Fällen finden, in denen es darauf ankommt, und nicht überall.
pdr
1
@ Tom Hawtin, wir alle wissen, dass es unvermeidlich ist, alles zu vermeiden null. Je mehr ich nach Alternativen suche null, desto mehr wird mir klar, dass die Verwendung nullmanchmal die sauberste Lösung ist. Mein gegebenes Beispiel ist meiner Meinung nach gar nicht so schlecht, und ich finde es eine angemessene Verwendung von nullbaren Typen.
Steven Jeuris
16

var erlaubt weniger ausführlichen Code, was die Lesbarkeit erhöht. Meiner Meinung nach sollte die Lesbarkeit nicht daran gemessen werden, wie viele Details Sie sehen, sondern wie viele Details sich auf den ersten Blick verbergen. Neben Linq-Beispielen ermöglicht var die Eingabe von Enten auf Quellcode-Ebene, anhand des folgenden Beispiels:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Wen kümmert es, welche Art von Beschriftung es gibt, solange sie die Eigenschaft Text enthält?

Kodismus
quelle
Jemand, der versucht zu verstehen, ob dies zB ein Winforms-Label oder ein WPF-Label ist.
Steven Jeuris
14
@Steven Jeuris: Das ist normalerweise eine bekannte Kontextinformation. Wenn nicht, nähern Sie sich dem Code auf falsche Weise.
Codism
Jemand, der wissen möchte, ob es sich dann um ein Standard-WPF-Label oder ein benutzerdefiniertes Label handelt? :)
Steven Jeuris
14
1. Sollte es diese Person wirklich interessieren, solange es sich um eine Beschriftung mit einer Texteigenschaft handelt? 2. Wenn dies einer der seltenen Fälle ist, für die sie WIRKLICH einen guten Grund zur Sorge haben, fragen Sie Intellisense. 3. Wenn sie Code in einer IDE ohne Intellisense bearbeiten, haben sie wahrscheinlich viel größere Unannehmlichkeiten als 'var' :)
KutuluMike 10.11.11
4
Jemand mit einem schlechten Sinn für Abstraktion.
Jim Balter
16

Ich habe keine ernsthaften Kommentare zum ??Operator, da ich noch nie eine Sprache mit einem solchen Operator verwendet habe. Was das betrifft var, programmieren die Leute in Sprachen wie Ruby, Python, Perl und PHP, die die ganze Zeit implizites Tippen haben. Muttersprachen dieser Sprachen erkennen, dass der formale Typ einer Variablen normalerweise irrelevantes Rauschen ist. Sie sind mehr daran interessiert, was die Variable kann tun , also seine strukturellen / Ente - Schnittstelle.

Ebenso programmiere ich meistens in D. D ist statisch getippt, hat aber das autoSchlüsselwort, was äquivalent zu ist var. Es wird als idiomatisch angesehen, es überall zu verwenden, es sei denn, Sie sehen eine spezielle Notwendigkeit, die Art von etwas entweder für den Leser oder (durch implizite Konvertierung) für den Compiler hervorzuheben. Außer gelegentlich bei der Verwendung als Funktionsrückgabetyp (dies ist in D zulässig) habe ich nie festgestellt, dass dies die Lesbarkeit beeinträchtigt, da ich beim Programmieren hauptsächlich an Struktur- / Enten-Schnittstellen denke, nicht an formale / nominative Typen.

Darüber hinaus ist die Verwendung von IMHO varüberall möglich ein gutes Beispiel für DRY. Der Typ von etwas sollte an einer und nur einer Stelle angegeben werden und dann automatisch weitergegeben werden, wann immer es weitergegeben werden muss. Wenn Sie verwenden varund sich der formale Typ der Variablen irgendwann ändern muss, werden die erforderlichen Änderungen vom Compiler automatisch überall dort weitergegeben, wo sie erforderlich sind, solange das Programm noch typenrichtig ist, anstatt dass der Programmierer jede Instanz manuell ändern muss . Dies ist eine gute Sache (TM).

dsimcha
quelle
13

Ich denke, das ist am Ende eine Frage für das Team. Wenn es für niemanden in meinem Team lesbar ist, werde ich es nicht verwenden, obwohl ich einige Male versuchen könnte, sie mit Beispielen zu überzeugen, oder indem ich auf ana- loge Abkürzungen (wie + =) hinweise, die sie besser lesbar finden.

Wenn ich aber alleine arbeite dann finde ich ?? und uneingeschränkt lesbar. Sogar

var a = b ?? c ?? d ?? e ?? "";

ist für mich ziemlich eindeutig.

Ternäre Operatoren und dynamicsind natürlich eine andere Sache.

pdr
quelle
4
Ich würde hier "String.Empty" verwenden.
Job
1
@Job, ehrlich gesagt, würde ich auch. Ich wollte etwas in diese Zeichenfolge einfügen und konnte dann an nichts denken :)
pdr
4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere
2
@ Xaade Sie können nie sicher genug sein. Die Verwendung von String.Empty oder "" ist jedoch eine persönliche Präferenz. Ich benutze "", weil es kürzer ist ...
Carra
12
@Xaade - wenn String.Emptyjemals zurückkehrt null, werden wir verdammt viele kaputte Codes finden.
Jesse C. Slicer
10

Das Argument für die Verwendung von? Operator war, nimmt es die Lesbarkeit im Code.

Wenn ich kurz darüber nachdenke, sagt mir dieser Kommentar, dass die Person, die den Kommentar abgibt, ihn nicht so gut versteht, wie er / sie es sollte. Es ist höchstwahrscheinlich in bestimmten Situationen der Fall, aber im Großen und Ganzen schätze ich etwas nicht ein, das das C # -Team offensichtlich aufgrund der "Lesbarkeit" für wichtig genug hielt, um es hinzuzufügen. Ich habe dies in der gleichen Kategorie von if(boolean_object)vs if(boolean_object == true). Einige Leute argumentieren , dass die zweite besser lesbar ist, aber in Wirklichkeit ist es nur das Hinzufügen zusätzlichen Code für jemanden / Art zu lesen, und in manchen Situationen können mehr verwirrend (denken if(boolean_object != false))

Meine Frage ist, passiert nicht dasselbe, wenn Sie anfangen, var zu verwenden?

Das C # -Team hat Ihnen erlaubt, nichts zu definieren, von dem Sie wissen, was es sein wird. Sofern ich nicht unbedingt definieren muss, was eine Variable sein soll (entweder ist es absolut wichtig, dass ein zurückgegebenes Objekt vom Typ x ist, oder es ist wirklich nicht lesbar), verwende ich var. var x = "MY_STRING";Ich weiß, dass es eine Saite ist, wenn ich sie mir ansehe. In Wahrheit ist es mir egal, dass es eine Saite ist, solange sie das tut, wofür ich sie brauche. Das Definieren des Variablentyps ist zu meinem Vorteil und nicht zum Vorteil des Compilers. Wenn etwas nicht stimmt, teilt der Compiler mir mit, wann es ausgeführt wird, wenn ich den falschen Variablentyp habe.

kemiller2002
quelle
0

Das varSchlüsselwort wird meiner Meinung nach am besten in den Situationen verwendet, für die es ursprünglich eingeführt wurde - LINQ-Abfragen. In diesen Abfragen hat der Typ des zurückgegebenen Ergebnisses häufig einen großen verschlungenen Namen, der schwer im Voraus zu bestimmen ist und dem Leser nicht hilft, die Funktionsweise Ihres Codes zu verstehen.

Allerdings var text = "Some text " + variableName + "some more text."ist das nur faul.

BEARBEITEN: @Jorg Sie haben auf eine gezielt vereinfachte Antwort gesprungen, aber nichts zur Diskussion hinzugefügt. OK, wie wäre es damit für ein besseres Beispiel: var items = doc.DocumentElement.FirstChild.ChildNodes;Wenn Sie den Typ daraus herausfinden können, gebe ich Ihnen einen Keks.

Josh Earl
quelle
18
Wenn Sie nicht herausfinden können, dass "Some text "es sich um ein handelt string, haben Sie viel größere Probleme als die Anzahl der vars in Ihrem Code.
Jörg W Mittag
3
Das Problem ist nicht var; Das Problem ist der beschissene Variablenname "items". Wenn Sie einen guten Variablennamen verwenden, ist nichts falsch daran var.
Kyralessa
3
Ich vermute (ohne hinzuschauen), dass Items eine Sammlung von XML-Knoten sind, von denen ich erwarte, dass sie alle Eigenschaften und Methoden einer Sammlung von XML-Knoten haben, und das ist wirklich alles, was ich wissen muss.
KutuluMike
Wenn Sie wissen möchten, für welchen Typ die Variable steht und nicht sofort erkennen können, fahren Sie mit der Maus darüber. Muss nicht viel herausfinden, um es zu tun.
scrwtp
1
"ist nur faul" - Dies ist kein Argument dagegen. Tatsächlich ist es überhaupt nicht intelligent.
Jim Balter
0

Ich habe ein grundlegendes Problem mit der Verwendung von var.

In diesem Beispiel ist alles Seite an Seite, aber das Problem sind wirklich große Lösungen mit gemeinsam genutzten Bibliotheken oder Projekten.

Bedenken Sie:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Was passiert, wenn GetMeAnObject von einer anderen Person geändert wird, um es ihren Bedürfnissen anzupassen?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

Die MainProgram-Methode hat einen großen roten Fehler bei .PerformOperation (). Was ist passiert? PerformOperation hat vorher einwandfrei funktioniert. Wir sehen uns die Methoden in theObject an und sie sind einfach spurlos verschwunden. Es war das letzte Mal dort und wir brauchen diese Methode. Sie könnten eine lange Zeit damit verbringen, Ihren Schwanz zu jagen und herauszufinden, warum MyFirstObject, wenn es eine Methode namens PerformOperation hat, jetzt nicht mehr sichtbar ist. Jeder "weiß", dass GetMeAnObject ein MyFirstObject zurückgibt. Es macht also keinen Sinn, das zu überprüfen.

Wenn Sie theObject explizit eingegeben hätten, würde in der Zeile, die GetMeAnObject aufruft, ein ungültiger Besetzungsfehler auftreten, und es wäre verblüffend, dass GetMeAnObject einen Typ zurückgibt, der nicht Ihren Erwartungen entspricht.

Kurz gesagt bedeutet explizite Deklaration, dass Sie wissen, was die Fehler bedeuten. Eine ungültige Umwandlung bedeutet, dass Sie einen Typ erwartet haben und ein anderer Typ zurückgegeben wurde. Ein nicht erkanntes Mitglied bedeutet, dass das Mitglied nicht erkannt wurde.

Hugh Phoenix-Hulme
quelle
10
Ein Kollege hat eine bahnbrechende Änderung am Code vorgenommen, die nicht von Tests abgedeckt wird, und Sie denken, das Problem ist var? Von der Sprache kann nicht erwartet werden, dass sie vor solchen Verhaltensweisen schützt. Was wäre, wenn sie MyFirstObject direkt geändert hätte? Es wäre immer noch kaputt gegangen, aber keine Syntax hätte Sie davon abhalten können. Ich würde dies sogar als Stärke betrachten var: Was wäre, wenn Sie statt MySecondObject jetzt stattdessen IMyFirstObject zurückgeben würden?
Phoshi
2
"Jeder" weiß ", dass GetMeAnObject ein MyFirstObject zurückgibt, daher macht es keinen Sinn, das zu überprüfen." Ich kann mir kein Szenario in der Programmierung vorstellen, in dem ich tatsächlich von meiner Erinnerung an GetMeAnObject abhängen würde, wenn ich debugge. Wenn ich überprüft hätte, dass PerformOperation nicht vorhanden ist, hätte ich den Code gesehen und nein, es ist für eine andere Klasse. Wenn in einer IDE die Klasse die Instanz öffnen würde, schaue ich mir den Typ des Objekts an. Wenn der Compiler den Fehler meldet, wird "Klasse MySecondObject hat keine Operation PerformOperation" angezeigt. Woher weiß das jeder?
Muhammad Alkarouri