Es ist ziemlich ärgerlich, alle meine Strings auf null
zu testen, bevor ich Methoden wie ToUpper()
, StartWith()
etc sicher anwenden kann.
Wenn der Standardwert von string
die leere Zeichenfolge wäre, müsste ich nicht testen, und ich würde meinen, dass er mit den anderen Werttypen wie int
oder double
konsistent ist. Nullable<String>
wäre sinnvoll.
Warum entschieden sich die Designer von C # dafür, null
als Standardwert für Zeichenfolgen zu verwenden?
Hinweis: Dies bezieht sich auf diese Frage , konzentriert sich jedoch mehr auf das Warum als darauf, was damit zu tun ist.
Warum ist der Standardwert des Zeichenfolgentyps null anstelle einer leeren Zeichenfolge?
Weil string
ein Referenztyp ist und der Standardwert für alle Referenztypen null
ist.
Es ist ziemlich ärgerlich, alle meine Zeichenfolgen auf Null zu testen, bevor ich sicher Methoden wie ToUpper (), StartWith () usw. anwenden kann.
Das stimmt mit dem Verhalten von Referenztypen überein. Vor dem Aufrufen ihrer Instanzmitglieder sollte ein Häkchen für eine Nullreferenz gesetzt werden.
Wenn der Standardwert von string der leere String wäre, müsste ich ihn nicht testen, und ich würde meinen, dass er mit den anderen Werttypen wie int oder double konsistenter ist.
Wenn Sie den Standardwert einem bestimmten Referenztyp zuweisen, der nicht null
ist, wird er inkonsistent .
Zusätzlich wäre _
Nullable<String>
_ sinnvoll.
Nullable<T>
arbeitet mit den Werttypen. Bemerkenswert ist die Tatsache, dass Nullable
nicht auf der ursprünglichen . NET-Plattform eingeführt wurde, so dass es eine Menge fehlerhaften Codes gegeben hätte, wenn sie diese Regel geändert hätten. ( Mit freundlicher Genehmigung @ jcolebrand )
Habib hat recht - weil string
ein Referenztyp ist.
Noch wichtiger ist jedoch, dass Sie not nicht bei jeder Verwendung auf null
prüfen müssen. Sie sollten wahrscheinlich eine ArgumentNullException
werfen, wenn jemand Ihrer Funktion eine null
-Referenz übergibt.
Hier ist die Sache - das Framework würde sowieso eine NullReferenceException
für Sie werfen, wenn Sie versuchen, .ToUpper()
für einen String aufzurufen. Beachten Sie, dass dieser Fall auch dann auftreten kann, wenn Sie Ihre Argumente für null
testen, da Eigenschaften oder Methoden der Objekte, die an Ihre Funktion als Parameter übergeben werden, zu null
ausgewertet werden können.
Es ist jedoch üblich, nach leeren Zeichenfolgen oder Nullen zu suchen. Daher bieten sie String.IsNullOrEmpty()
und String.IsNullOrWhiteSpace()
nur für diesen Zweck an.
Sie könnten eine Erweiterungsmethode schreiben (was es wert ist):
public static string EmptyNull(this string str)
{
return str ?? "";
}
Das funktioniert jetzt sicher:
string str = null;
string upper = str.EmptyNull().ToUpper();
Leere Zeichenfolgen und Nullen unterscheiden sich grundsätzlich. Ein Nullwert ist das Fehlen eines Werts und eine leere Zeichenfolge ist ein leerer Wert.
Die Programmiersprache, die Annahmen über den "Wert" einer Variablen vornimmt, in diesem Fall eine leere Zeichenfolge, ist so gut wie das Initialisieren der Zeichenfolge mit einem anderen Wert, der kein Nullreferenzproblem verursacht.
Wenn Sie das Handle an diese Zeichenfolgenvariable an andere Teile der Anwendung übergeben, kann der Code nicht überprüfen, ob Sie absichtlich einen leeren Wert übergeben haben oder vergessen haben, den Wert dieser Variablen auszufüllen.
Eine andere Gelegenheit, bei der dies ein Problem darstellen würde, ist, wenn die Zeichenfolge ein Rückgabewert einer Funktion ist. Da string ein Referenztyp ist und technisch einen Wert als null und leer haben kann, kann die Funktion auch technisch einen Nullwert oder einen leeren Wert zurückgeben (dies steht jedoch nichts dagegen). Da es zwei Vorstellungen von "Abwesenheit eines Wertes" gibt, d. H. Einer leeren Zeichenfolge und einer Null, muss der gesamte Code, der diese Funktion beansprucht, zwei Prüfungen durchführen. Einer für leer und der andere für null.
Kurz gesagt, es ist immer gut, nur eine Darstellung für einen einzelnen Zustand zu haben. Weitere Informationen zu leeren und Nullen finden Sie unter den Links unten.
https://softwareengineering.stackexchange.com/questions/32578/sql-empty-string-vs-null-value
Sie können auch (ab VS2015 und dem neuen Compiler) Folgendes verwenden
string myString = null;
string result = myString?.ToUpper();
Das Zeichenfolgenergebnis ist null.
Weil eine Zeichenfolgenvariable eine Referenz ist, keine Instanz .
Die Initialisierung auf Empty wäre standardmäßig möglich gewesen, hätte jedoch zu vielen Inkonsistenzen auf der ganzen Karte geführt.
Der grundlegende Grund/das grundlegende Problem besteht darin, dass die Designer der CLS-Spezifikation (die definiert, wie Sprachen mit .net interagieren) keine Mittel definiert haben, mit denen Klassenmitglieder angeben könnten, dass sie direkt aufgerufen werden müssen, statt über callvirt
, ohne dass der Aufrufer ausgeführt wird eine Nullreferenzprüfung; Es bot auch keine Möglichkeit, Strukturen zu definieren, die keinem "normalen" Boxen unterliegen würden.
Wenn die CLS-Spezifikation ein solches Mittel definiert hätte, könnte .net konsequent der durch das Common Object Model (COM) eingerichteten Führung folgen, unter der eine NULL-Zeichenfolge als semantisch einer leeren Zeichenfolge gleichwertig betrachtet wurde Benutzerdefinierte unveränderliche Klassentypen, die eine Wertesemantik haben sollen, um ebenfalls Standardwerte zu definieren. Was würde im Wesentlichen für jedes Mitglied von String
passieren, z. Length
soll so etwas wie [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
geschrieben werden. Dieser Ansatz hätte sehr schöne Semantik für Dinge geboten, die sich wie Werte verhalten sollten, aber aufgrund von Implementierungsproblemen auf dem Heap gespeichert werden müssen. Die größte Schwierigkeit bei diesem Ansatz besteht darin, dass die Semantik der Konvertierung zwischen solchen Typen und Object
etwas trübe werden kann.
Ein alternativer Ansatz wäre gewesen, die Definition spezieller Strukturtypen zuzulassen, die nicht von Object
geerbt wurden, sondern benutzerdefinierte Box- und Unboxing-Vorgänge hatten (die in einen anderen Klassentyp konvertiert würden). Bei einem solchen Ansatz würde es einen Klassentyp NullableString
geben, der sich jetzt wie String verhält, und einen benutzerdefinierten Stiltyp String
, der ein einzelnes privates Feld Value
vom Typ String
enthalten würde. Der Versuch, eine String
in NullableString
oder Object
umzuwandeln, würde Value
zurückgeben, wenn sie nicht null ist, oder String.Empty
wenn null. Beim Versuch, in String
umzuwandeln, würde ein Verweis auf eine NullableString
-Instanz, der nicht null ist, den Verweis in Value
speichern (möglicherweise wird null gespeichert, wenn die Länge null ist). Bei einem anderen Verweis würde eine Ausnahme ausgelöst.
Obwohl Zeichenfolgen auf dem Heap gespeichert werden müssen, gibt es konzeptionell keinen Grund, warum sie nicht verhalten Wertetypen sein sollten, deren Standardwert nicht Null ist. Wenn sie als "normale" Struktur gespeichert werden, die eine Referenz enthält, wäre dies für Code, der sie als Typ "string" verwendet hat, effizient gewesen, hätte jedoch eine zusätzliche Schicht von Indirektion und Ineffizienz beim "Casting" in "object" hinzugefügt. Obwohl ich nicht vorhersehe, dass .net zu diesem späten Zeitpunkt eine der oben genannten Funktionen hinzufügt, werden Konstrukteure zukünftiger Frameworks möglicherweise in Betracht ziehen.
Warum entschieden sich die Designer von C # für die Verwendung von Null als Standardwert für Streicher
Da es sich bei Zeichenfolgen um Referenztypen handelt, sind Referenztypen der Standardwert null
. Variablen von Referenztypen speichern Verweise auf die tatsächlichen Daten.
Verwenden Sie für diesen Fall das Schlüsselwort default
.
string str = default(string);
str
ist eine string
, es handelt sich also um einen Referenztyp. Der Standardwert ist null
.
int str = (default)(int);
str
ist eine int
, also ein value-Typ. Der Standardwert ist zero
.
Wenn der Standardwert von
string
die leere Zeichenfolge wäre, müsste ich nicht testen
Falsch! Das Ändern des Standardwerts ändert nichts an der Tatsache, dass es sich um einen Referenztyp handelt, und jemand kann dennoch explizit set die Referenz als null
festlegen.
Zusätzlich wäre
Nullable<String>
sinnvoll.
Wahrer Punkt Es wäre sinnvoller, null
für keinen Referenztyp zuzulassen, stattdessen Nullable<TheRefType>
für dieses Feature zu benötigen.
Warum entschieden sich die Designer von C # dafür,
null
als Standardwert für Zeichenfolgen zu verwenden?
Übereinstimmung mit anderen Referenztypen. Warum erlaube ich null
überhaupt in Referenztypen? Wahrscheinlich so, dass es sich wie C anfühlt, obwohl dies eine fragwürdige Entwurfsentscheidung in einer Sprache ist, die auch Nullable
bereitstellt.
Wenn Sie bei der Zuweisung Ihrer String-Variablen den Operator ??
verwenden, kann dies möglicherweise hilfreich sein.
string str = SomeMethodThatReturnsaString() ?? "";
// if SomeMethodThatReturnsaString() returns a null value, "" is assigned to str.
Ein String ist ein unveränderliches Objekt. Wenn ein Wert angegeben wird, wird der alte Wert nicht aus dem Speicher gelöscht, sondern verbleibt am alten Speicherort, und der neue Wert wird an einem neuen Speicherort abgelegt. Wenn der Standardwert von String a
String.Empty
wäre, würde der String.Empty
-Block im Speicher verschwendet werden, wenn er seinen ersten Wert erhält.
Obwohl es sich um ein Minuszeichen handelt, könnte es zu einem Problem werden, wenn ein großes String-Array mit den Standardwerten von String.Empty
initialisiert wird. Natürlich können Sie immer die veränderliche StringBuilder
-Klasse verwenden, wenn dies ein Problem sein würde.
Da string ein Referenztyp ist und der Standardwert für den Referenztyp null ist.
Das string
-Schlüsselwort hat Sie vielleicht verwirrt, da es genau wie jede andere value type -Deklaration aussieht, aber es ist eigentlich ein Alias für System.String
, wie in diese Frage erläutert.
Auch die dunkelblaue Farbe in Visual Studio und der Kleinbuchstabe können dazu führen, dass es sich um eine struct
handelt.
Nullable-Typen kamen erst in 2.0.
Wenn nullfähige Typen am Anfang der Sprache erstellt worden wären, wäre string nicht nullable und string gewesen. wäre nullfähig gewesen Sie konnten dies jedoch nicht zur Rückwärtskompatibilität tun.
Viele Leute sprechen über Ref-Typ oder Nicht-Ref-Typ, aber String ist eine außergewöhnliche Klasse, und es wären Lösungen gefunden worden, um dies zu ermöglichen.