Es ist ziemlich ärgerlich alle für meine Saiten zu testen , null
bevor ich Methoden sicher anwenden kann , wie ToUpper()
, StartWith()
etc ...
Wenn der Standardwert von string
die leere Zeichenfolge wäre, müsste ich nicht testen, und ich würde das Gefühl haben, dass er mit den anderen Werttypen wie int
oder double
zum Beispiel konsistenter ist . Zusätzlich Nullable<String>
würde Sinn machen.
Warum haben sich die Designer von C # für die Verwendung null
als Standardwert für Zeichenfolgen entschieden?
Hinweis: Dies bezieht sich auf diese Frage , konzentriert sich jedoch mehr auf das Warum als auf das, was damit zu tun ist.
c#
string
default-value
Marcel
quelle
quelle
null
(und ich empfehle Ihnen außerdem,null
Zeichenfolgen konzeptionell als verschiedene Dinge zu behandeln und zu leeren). Ein Nullwert kann das Ergebnis eines Fehlers sein, während eine leere Zeichenfolge eine andere Bedeutung haben sollte.Antworten:
Da
string
ist ein Referenztyp und der Standardwert für alle Referenztypen istnull
.Dies steht im Einklang mit dem Verhalten von Referenztypen. Vor dem Aufrufen ihrer Instanzmitglieder sollte eine Überprüfung auf eine Nullreferenz vorgenommen werden.
Das Zuweisen des Standardwerts zu einem bestimmten Referenztyp
null
, der nicht inkonsistent wäre .Nullable<T>
arbeitet mit den Werttypen. Bemerkenswert ist die Tatsache, dass sieNullable
nicht auf der ursprünglichen .NET-Plattform eingeführt wurde, so dass es viel fehlerhaften Code gegeben hätte, wenn sie diese Regel geändert hätten. ( Mit freundlicher Genehmigung von @jcolebrand )quelle
String
, mit Ausnahme von (1) dem werttypischen Verhalten, einen verwendbaren Standardwert zu haben, und (2) einer unglücklichen zusätzlichen Ebene der Box-Indirektion, wenn er angewendet wirdObject
. Angesichts der Tatsache, dass die Heap-Darstellung vonstring
einzigartig ist, wäre eine spezielle Behandlung zur Vermeidung von zusätzlichem Boxen keine große Herausforderung gewesen (tatsächlich wäre es auch für andere Typen eine gute Sache, nicht standardmäßige Boxverhaltensweisen angeben zu können).Habib hat recht - weil
string
es sich um einen Referenztyp handelt.Noch wichtiger ist jedoch, dass Sie nicht
null
jedes Mal nachsehen müssen, wenn Sie es verwenden. Sie sollten wahrscheinlichArgumentNullException
einenull
Referenz werfen, wenn jemand Ihre Funktion übergibt .Hier ist die Sache - das Framework würde
NullReferenceException
sowieso ein für Sie werfen, wenn Sie versuchen würden,.ToUpper()
eine Zeichenfolge aufzurufen . Denken Sie daran, dass dieser Fall auch dann auftreten kann, wenn Sie Ihre Argumente testen,null
da eine Eigenschaft oder Methode für die Objekte, die als Parameter an Ihre Funktion übergeben werden, ausgewertet werden kannnull
.That being said, für leere Strings oder nulls Überprüfung eine gemeinsame Sache zu tun ist , so bieten sie
String.IsNullOrEmpty()
undString.IsNullOrWhiteSpace()
nur für diesen Zweck.quelle
NullReferenceException
( msdn.microsoft.com/en-us/library/ms173163.aspx ); Sie werfen ein,ArgumentNullException
wenn Ihre Methode keine Null-Refs akzeptieren kann. Außerdem sind NullRefs normalerweise eine der schwierigeren Ausnahmen bei der Diagnose, wenn Sie Probleme beheben. Daher halte ich die Empfehlung, nicht auf Null zu prüfen, nicht für sehr gut.ArgumentNullException
hat den zusätzlichen Vorteil, dass der Parametername angegeben werden kann. Während des Debuggens spart dies ... ähm, Sekunden. Aber wichtige Sekunden.Sie könnten eine Erweiterungsmethode schreiben (für das, was es wert ist):
Das funktioniert jetzt sicher:
quelle
.EmptyNull()
, verwenden Sie es(str ?? "")
stattdessen einfach dort, wo es benötigt wird. Trotzdem stimme ich dem in @ DaveMarkles Kommentar zum Ausdruck gebrachten Gefühl zu: Sie sollten es wahrscheinlich nicht tun.null
undString.Empty
sind konzeptionell unterschiedlich, und Sie können nicht unbedingt das gleiche wie das andere behandeln.Ab C # 6.0 können Sie auch Folgendes verwenden
Das String-Ergebnis ist null.
quelle
public string Name { get; set; } = string.Empty;
Leere Zeichenfolgen und Nullen unterscheiden sich grundlegend. Eine Null ist das Fehlen eines Werts und eine leere Zeichenfolge ist ein Wert, der leer ist.
Die Programmiersprache, die Annahmen über den "Wert" einer Variablen, in diesem Fall eine leere Zeichenfolge, trifft, ist so gut wie das Initiieren der Zeichenfolge mit einem anderen Wert, der kein Nullreferenzproblem verursacht.
Wenn Sie das Handle an diese Zeichenfolgenvariable an andere Teile der Anwendung übergeben, kann dieser Code nicht überprüfen, ob Sie absichtlich einen leeren Wert übergeben haben oder vergessen haben, den Wert dieser Variablen aufzufüllen.
Eine andere Möglichkeit, bei der dies ein Problem darstellen würde, besteht darin, dass die Zeichenfolge ein Rückgabewert einer Funktion ist. Da string ein Referenztyp ist und technisch einen Wert wie null und leer haben kann, kann die Funktion auch technisch null oder leer zurückgeben (nichts hindert sie daran). Da es nun zwei Begriffe für das "Fehlen eines Werts" gibt, dh eine leere Zeichenfolge und eine Null, muss der gesamte Code, der diese Funktion verwendet, zwei Überprü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 Staat zu haben. Weitere Informationen zu Leerzeichen und Nullen finden Sie unter den folgenden Links.
/software/32578/sql-empty-string-vs-null-value
NULL vs Leer beim Umgang mit Benutzereingaben
quelle
null
die leere Zeichenfolge darstellen. Es gibt eine Reihe von Möglichkeiten, wie .net eine ähnliche Semantik hätte implementieren können, wenn sie sich dafür entschieden hätten, insbesondere angesichtsString
einer Reihe von Merkmalen, die es ohnehin zu einem eindeutigen Typ machen [z. B. sind es und die beiden Array-Typen die einzigen Typen, deren Zuordnung Größe ist nicht konstant].Der grundlegende Grund / das grundlegende Problem besteht darin, dass die Designer der CLS-Spezifikation (die definiert, wie Sprachen mit .net interagieren) kein Mittel definiert haben, mit dem Klassenmitglieder festlegen können, dass sie direkt und nicht über aufgerufen werden müssen
callvirt
, ohne dass der Aufrufer a ausführt Nullreferenzprüfung; Es bot auch keine Möglichkeit, Strukturen zu definieren, die keinem "normalen" Boxen unterliegen würden.Hätte die CLS-Spezifikation ein solches Mittel definiert, wäre es für .net möglich, konsequent dem vom Common Object Model (COM) festgelegten Vorsprung zu folgen, unter dem eine Nullzeichenfolgenreferenz als semantisch äquivalent zu einer leeren Zeichenfolge angesehen wurde, und für andere Benutzerdefinierte unveränderliche Klassentypen, die eine Wertsemantik haben sollen, um ebenfalls Standardwerte zu definieren. Was im Wesentlichen passieren würde, wäre, dass jedes Mitglied von
String
, z. B.Length
als so etwas geschrieben wird[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Dieser Ansatz hätte eine 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 TypenObject
etwas trübe werden kann.Ein alternativer Ansatz wäre gewesen, die Definition spezieller Strukturtypen zu ermöglichen, die nicht von geerbten,
Object
sondern benutzerdefinierte Box- und Unboxing-Operationen erbten (die in einen anderen Klassentyp konvertiert wurden). Bei einem solchen Ansatz würde es einen Klassentyp geben,NullableString
der sich jetzt wie eine Zeichenfolge verhält, und einen Strukturtyp mit benutzerdefinierten BoxenString
, der ein einzelnes privates FeldValue
vom Typ enthältString
. Der Versuch, aString
inNullableString
oder zu konvertieren , wirdObject
zurückgegeben,Value
wenn er nicht null oderString.Empty
null ist. Beim Versuch,String
in eineNullableString
Instanz umzuwandeln, die nicht null ist , wird die Referenz inValue
gespeichert (möglicherweise wird null gespeichert, wenn die Länge null ist). Das Wirken einer anderen Referenz würde eine Ausnahme auslösen.Obwohl Zeichenfolgen auf dem Heap gespeichert werden müssen, gibt es konzeptionell keinen Grund, warum sie sich nicht wie Werttypen verhalten sollten , die einen Standardwert ungleich Null haben. Wenn sie als "normale" Struktur gespeichert worden wären, die eine Referenz enthielt, wäre dies für Code, der sie als Typ "Zeichenfolge" verwendete, effizient gewesen, hätte jedoch beim Umwandeln in "Objekt" eine zusätzliche Ebene der Indirektion und Ineffizienz hinzugefügt. Obwohl ich nicht vorsehe, dass .net zu diesem späten Zeitpunkt eine der oben genannten Funktionen hinzufügt, könnten Designer zukünftiger Frameworks in Betracht ziehen, sie einzubeziehen.
quelle
Nullable<>
, können Zeichenfolgen natürlich als Werttypen erneut implementiert werden. Ich kann nicht über die Kosten und den Nutzen einer solchen Wahl sprechen.string
effizienter ist alsNullable<string>
dies der Fall wäre, ist die Verwendung der "effizienteren" Methode aufwändiger als die Verwendung des gleichen Ansatzes für alle nullbaren Datendatenbankwerte.Da eine Zeichenfolgenvariable eine Referenz und keine Instanz ist .
Eine standardmäßige Initialisierung auf "Leer" wäre möglich gewesen, hätte jedoch auf der ganzen Linie viele Inkonsistenzen verursacht.
quelle
string
ein Referenztyp sein müsste. Natürlich müssen die tatsächlichen Zeichen, aus denen die Zeichenfolge besteht, auf dem Heap gespeichert werden. Angesichts der Menge an dedizierter Unterstützung, die Zeichenfolgen bereits in der CLR haben, wäre es kein Problem,System.String
ein Werttyp mit a zu sein einzelnes privates FeldValue
vom TypHeapString
. Dieses Feld wäre ein Referenztyp und würde standardmäßig verwendet werdennull
, aber eineString
Struktur, derenValue
Feld null war, würde sich wie eine leere Zeichenfolge verhalten. Der einzige Nachteil dieses Ansatzes wäre ...String
toObject
in Abwesenheit von Sonderfallcode zur Laufzeit die Erstellung einer Box-String
Instanz auf dem Heap verursachen würde, anstatt einfach einen Verweis auf das zu kopierenHeapString
..Length
usw., sodass Instanzen, die gelten Eine Nullreferenz würde nicht versuchen, sie zu dereferenzieren, sondern sich für eine leere Zeichenfolge entsprechend verhalten. Ob das Framework mit dieserstring
Implementierung besser oder schlechter wäre , wenn mandefault(string)
eine leere Zeichenfolge sein wollte ...string
ein Werttyp-Wrapper in einem Referenztyp-Feld zu sein, wäre der Ansatz, der die wenigsten Änderungen an anderen Teilen von .net erfordert [in der Tat, wenn man bereit wäre, eine Konvertierung vonString
zu akzeptieren ,Object
um ein zusätzliches Element in einer Box zu erstellen, man könnte einfachString
eine gewöhnliche Struktur mit einem Typfeld sein,Char[]
das sie niemals enthüllte. Ich denke, einHeapString
Typ wäre wahrscheinlich besser, aber in mancher Hinsicht wäre die Werttyp-Zeichenfolge mit aChar[]
einfacher.Da Zeichenfolgen Referenztypen sind , sind Referenztypen Standardwerte
null
. Variablen von Referenztypen speichern Verweise auf die tatsächlichen Daten.Verwenden wir
default
für diesen Fall das Schlüsselwort.str
ist astring
, also ist es ein Referenztyp , also ist der Standardwertnull
.str
ist einint
, also ist es ein Werttyp , also ist der Standardwertzero
.quelle
Falsch! Das Ändern des Standardwerts ändert nichts an der Tatsache, dass es sich um einen Referenztyp handelt und jemand die Referenz weiterhin explizit festlegen kann
null
.Wahrer Punkt. Es wäre sinnvoller,
null
keine Referenztypen zuzulassen , sondern diese Funktion zu benötigenNullable<TheRefType>
.Konsistenz mit anderen Referenztypen. Warum überhaupt
null
Referenztypen zulassen ? Wahrscheinlich, damit es sich wie C anfühlt, obwohl dies eine fragwürdige Entwurfsentscheidung in einer Sprache ist, die auch bietetNullable
.quelle
Wenn Sie
??
beim Zuweisen Ihrer Zeichenfolgenvariablen den Operator verwenden, kann dies möglicherweise hilfreich sein.quelle
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. Also , wenn der Standardwert
String a
warString.Empty
, würde es den AbfallString.Empty
Block im Speicher , wenn er seinen ersten Wert gegeben wurde.Obwohl es winzig erscheint, kann es beim Initialisieren eines großen Arrays von Zeichenfolgen mit Standardwerten von zu einem Problem werden
String.Empty
. Natürlich können Sie immer die veränderbareStringBuilder
Klasse verwenden, wenn dies ein Problem sein sollte.quelle
String.Empty
. Irre ich michstring
eine leere Zeichenfolge ist, besteht darin, alle Bits Null als Darstellung einer leeren Zeichenfolge zuzulassen. Es gibt eine Reihe von Möglichkeiten, wie dies erreicht werden kann, aber ich denke nicht, dass es erforderlich ist, Verweise auf zu initialisierenString.Empty
.String.Empty
oder wäre""
.string
Speicherorten hätte auch das Ändern des Initialisierungsverhaltens aller Strukturen oder Klassen mit Typfeldern erforderlich gemachtstring
. Dies würde eine ziemlich große Änderung im Design von .net darstellen, das derzeit erwartet, jeden Typ auf Null zu initialisieren, ohne darüber nachdenken zu müssen, was es ist, abgesehen von seiner Gesamtgröße.Da string ein Referenztyp ist und der Standardwert für den Referenztyp null ist.
quelle
Vielleicht hat Sie das
string
Schlüsselwort verwirrt, da es genau wie jede andere Werttypdeklaration aussieht , aber es ist tatsächlich ein Alias für,System.String
wie in dieser Frage erläutert .Auch die dunkelblaue Farbe in Visual Studio und der Kleinbuchstabe können irreführen, wenn man denkt, dass es sich um eine handelt
struct
.quelle
object
Schlüsselwort? Zugegeben, das wird weit weniger genutzt alsstring
.int
ist ein Alias fürSystem.Int32
. Worauf willst du hinaus? :)System.Int32
einStruct
so einen Standardwert, währendSystem.String
eine istClass
von einem Zeiger mit Standardwertnull
. Sie werden visuell in derselben Schriftart / Farbe dargestellt. Ohne Wissen kann man denken, dass sie sich genauso verhalten (= einen Standardwert haben). Meine Antwort wurde mit einer kognitiven Psychologie-Idee von en.wikipedia.org/wiki/Cognitive_psychology dahinter geschrieben :-)Nullable-Typen kamen erst in 2.0.
Wenn am Anfang der Sprache nullbare Typen erstellt worden wären, wäre die Zeichenfolge nicht nullwertfähig und die Zeichenfolge? wäre nullbar gewesen. Aufgrund der Abwärtskompatibilität konnten sie dies jedoch nicht tun.
Viele Leute sprechen über Ref-Typ oder nicht Ref-Typ, aber String ist eine ungewöhnliche Klasse und es wären Lösungen gefunden worden, um dies zu ermöglichen.
quelle