it-swarm.com.de

Warum ist der Standardwert des Zeichenfolgentyps null anstelle einer leeren Zeichenfolge?

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.

195
Marcel

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 )

297
Habib

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.

40
Dave Markle

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();
23
Rango

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

NULL vs Leer bei Benutzereingaben

14
Nerrve

Sie können auch (ab VS2015 und dem neuen Compiler) Folgendes verwenden

string myString = null;
string result = myString?.ToUpper();

Das Zeichenfolgenergebnis ist null.

12
russelrillema

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. 

5
Henk Holterman

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.

5
supercat

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.

5
Soner Gönül

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.

4
Dan Burton

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.
3
Amen JLILI

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 aString.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.

2
djv

Da string ein Referenztyp ist und der Standardwert für den Referenztyp null ist.

2
Akshay

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.

0

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.

0
Thomas Koelle