Antworten:
In .NET vor Version 2.0, ""
erstellt ein Objekt , während string.Empty
kein Objekt erstellt ref , was macht string.Empty
effizienter.
In Version 2.0 und höher von .NET ""
beziehen sich alle Vorkommen von auf dasselbe Zeichenfolgenliteral, was bedeutet, dass ""
es äquivalent zu .Empty
, aber immer noch nicht so schnell ist wie .Length == 0
.
.Length == 0
ist die schnellste Option, .Empty
sorgt aber für etwas saubereren Code.
Weitere Informationen finden Sie in der .NET-Spezifikation .
string.IsNullOrEmpty( stringVar )
.
Was ist der Unterschied zwischen String.Empty und "" und sind sie austauschbar?
string.Empty
ist ein schreibgeschütztes Feld, während ""
es sich um eine Kompilierungszeitkonstante handelt. Orte, an denen sie sich anders verhalten, sind:
Standardparameterwert in C # 4.0 oder höher
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Groß- / Kleinschreibung in der switch-Anweisung
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Attributargumente
[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type
String.Empty
in den meisten Fällen als Argument übergeben können. Sie haben Recht, dass alle Beispiele dies zeigen, you simply can't put a (run-time) "value" into (compile-time) metadata
und das ist es, was die Beispiele zeigen sollen.
Die vorherigen Antworten waren für .NET 1.1 korrekt (siehe Datum des verlinkten Beitrags: 2003). Ab .NET 2.0 und höher gibt es im Wesentlichen keinen Unterschied. Die JIT verweist ohnehin auf dasselbe Objekt auf dem Heap.
Gemäß der C # -Spezifikation, Abschnitt 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx
Jedes String-Literal führt nicht unbedingt zu einer neuen String-Instanz. Wenn zwei oder mehr Zeichenfolgenliterale, die dem Zeichenfolgengleichheitsoperator (Abschnitt 7.9.7) entsprechen, in derselben Assembly angezeigt werden, beziehen sich diese Zeichenfolgenliterale auf dieselbe Zeichenfolgeninstanz.
Jemand erwähnt dies sogar in den Kommentaren von Brad Abrams Beitrag
Zusammenfassend ist das praktische Ergebnis von "" vs. String.Empty gleich Null. Die JIT wird es am Ende herausfinden.
Ich persönlich habe festgestellt, dass die JIT viel schlauer ist als ich, und deshalb versuche ich, mit solchen Micro-Compiler-Optimierungen nicht zu schlau zu werden. Die JIT wird sich für () -Schleifen entfalten, redundanten Code, Inline-Methoden usw. besser und zu angemesseneren Zeiten entfernen, als ich oder der C # -Compiler jemals zuvor erwartet hätten. Lass die JIT ihren Job machen :)
String.Empty
ist ein Nur - Lese - während - Feld ""
ist ein const . Dies bedeutet, dass Sie String.Empty
eine switch-Anweisung nicht verwenden können , da sie keine Konstante ist.
default
Schlüsselworts können wir die Lesbarkeit fördern, versehentliche Änderungen verhindern und eine Konstante für die Kompilierungszeit haben. Um ehrlich zu sein, denke ich immer noch, dass String.Empty besser lesbar als Standard ist, aber langsamer zu tippen
Ein weiterer Unterschied besteht darin, dass String.Empty einen größeren CIL-Code generiert. Während der Code für die Referenzierung von "" und String.Empty gleich lang ist, optimiert der Compiler die String-Verkettung (siehe Eric Lipperts Blog-Beitrag ) nicht für String.Empty-Argumente. Die folgenden äquivalenten Funktionen
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
Generieren Sie diese IL
.method private hidebysig instance string foo() cil managed
{
.maxstack 8
L_0000: ldstr "foo"
L_0005: ret
}
.method private hidebysig instance string bar() cil managed
{
.maxstack 8
L_0000: ldstr "bar"
L_0005: ldsfld string [mscorlib]System.String::Empty
L_000a: call string [mscorlib]System.String::Concat(string, string)
L_000f: ret
}
"bar " + (ok ? "" : "error")
Die obigen Antworten sind technisch korrekt, aber was Sie wirklich verwenden möchten, um die beste Lesbarkeit des Codes und die geringste Wahrscheinlichkeit einer Ausnahme zu erzielen, ist String.IsNullOrEmpty (s)
--foo=$BAR
möchten Sie wahrscheinlich den Unterschied zwischen dem Vergessen, eine env var festzulegen, und dem Nichtübergeben des Flags erkennen. string.IsNullOrEmpty
ist oft ein Code-Geruch, dass Sie Ihre Eingaben nicht richtig validiert haben oder seltsame Dinge tun. Sie sollten im Allgemeinen keine leeren Zeichenfolgen akzeptieren, wenn Sie diese wirklich verwenden möchten null
, oder so etwas wie einen Vielleicht / Option-Typ.
Ich benutze String.Empty
eher als ""
aus einem einfachen, aber nicht offensichtlichen Grund:
""
und ""
sind NICHT gleich, der erste enthält tatsächlich 16 Zeichen mit einer Breite von Null. Natürlich wird kein kompetenter Entwickler Zeichen mit einer Breite von Null in seinen Code einfügen, aber wenn sie dort ankommen, kann dies ein Alptraum für die Wartung sein.
Anmerkungen:
In diesem Beispiel habe ich U + FEFF verwendet .
Sie sind sich nicht sicher, ob SO diese Zeichen essen wird, aber versuchen Sie es selbst mit einem der vielen Zeichen mit der Breite Null
Ich bin nur dank https://codegolf.stackexchange.com/ darauf gestoßen.
Verwenden Sie String.Empty
eher als ""
.
Dies ist mehr für die Geschwindigkeit als für die Speichernutzung, aber es ist ein nützlicher Tipp. Das
""
ist ein Literal und fungiert daher als Literal: Bei der ersten Verwendung wird es erstellt und für die folgenden Verwendungen wird seine Referenz zurückgegeben. Es wird nur eine Instanz von""
gespeichert, egal wie oft wir sie verwenden! Ich sehe hier keine Gedächtnisstrafen. Das Problem ist, dass jedes Mal""
, wenn das verwendet wird, eine Vergleichsschleife ausgeführt wird, um zu überprüfen, ob sich das""
bereits im internen Pool befindet. Auf der anderen SeiteString.Empty
befindet sich ein Verweis auf eine""
in der .NET Framework-Speicherzone gespeicherte Zone .String.Empty
zeigt auf dieselbe Speicheradresse für VB.NET- und C # -Anwendungen. Warum also jedes Mal nach einer Referenz suchen,""
wenn Sie diese Referenz in haben?String.Empty
?
Referenz: String.Empty
vs.""
String.Empty erstellt kein Objekt, während "" dies tut. Der hier erwähnte Unterschied ist jedoch trivial.
Alle Instanzen von "" sind das gleiche, internierte Zeichenfolgenliteral (oder sollten es sein). Sie werden also nicht jedes Mal, wenn Sie "" verwenden, ein neues Objekt auf den Heap werfen, sondern nur einen Verweis auf dasselbe internierte Objekt erstellen. Trotzdem bevorzuge ich string.Empty. Ich denke, es macht Code lesbarer.
Es ist einfach egal!
Einige frühere Diskussionen darüber:
http://www.codinghorror.com/blog/archives/000185.html
string mystring = "";
ldstr ""
ldstr
verschiebt einen neuen Objektverweis auf ein in den Metadaten gespeichertes Zeichenfolgenliteral.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
schiebt den Wert eines statischen Feldes auf den Auswertungsstapel
Ich neige dazu, String.Empty
anstatt zu verwenden, ""
weil IMHO es klarer und weniger VB-ish ist.
Eric Lippert schrieb (17. Juni 2013):
"Der erste Algorithmus, an dem ich jemals im C # -Compiler gearbeitet habe, war der Optimierer, der Zeichenfolgenverkettungen verarbeitet. Leider konnte ich diese Optimierungen nicht in die Roslyn-Codebasis portieren, bevor ich ging. Hoffentlich wird es jemand tun." Komm schon! "
Hier sind einige Roslyn x64- Ergebnisse vom Januar 2019. Trotz der Konsensbemerkungen der anderen Antworten auf dieser Seite scheint es mir nicht, dass die aktuelle x64-JIT alle diese Fälle identisch behandelt, wenn alles gesagt und getan ist.
Beachten Sie jedoch insbesondere, dass nur eines dieser Beispiele tatsächlich aufgerufen wird String.Concat
, und ich vermute, dass dies aus Gründen der unklaren Korrektheit geschieht (im Gegensatz zu einem Optimierungsversehen). Die anderen Unterschiede scheinen schwerer zu erklären.
default (String) + {default (String), "", String.Empty}
static String s00() => default(String) + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s01() => default(String) + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s02() => default(String) + String.Empty;
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
"" + {default (String), "", String.Empty}
static String s03() => "" + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s04() => "" + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
add rsp,28h
ret
static String s05() => "" + String.Empty;
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
String.Empty + {default (String), "", String.Empty}
static String s06() => String.Empty + default(String);
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
static String s07() => String.Empty + "";
mov rax,[String::Empty]
mov rax,qword ptr [rax]
mov rdx,rax
test rdx,rdx
jne _L
mov rdx,rax
_L: mov rax,rdx
add rsp,28h
ret
static String s08() => String.Empty + String.Empty;
mov rcx,[String::Empty]
mov rcx,qword ptr [rcx]
mov qword ptr [rsp+20h],rcx
mov rcx,qword ptr [rsp+20h]
mov rdx,qword ptr [rsp+20h]
call F330CF60 ; <-- String.Concat
nop
add rsp,28h
ret
Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false
Aus Sicht von Entity Framework: EF-Versionen 6.1.3 scheinen String.Empty und "" bei der Validierung unterschiedlich zu behandeln.
string.Empty wird zu Validierungszwecken als Nullwert behandelt und löst einen Validierungsfehler aus, wenn er in einem erforderlichen (zugewiesenen) Feld verwendet wird. Dabei wird "" die Validierung bestehen und den Fehler nicht auslösen.
Dieses Problem kann in EF 7+ behoben werden. Referenz: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Bearbeiten: [Erforderlich (AllowEmptyStrings = true)] behebt dieses Problem und ermöglicht die Validierung von string.Empty.
Da String.Empty keine Konstante zur Kompilierungszeit ist, können Sie sie nicht als Standardwert in der Funktionsdefinition verwenden.
public void test(int i=0,string s="")
{
// Function Body
}
public void test(int i=0, string s=string.Empty) {}
wird nicht kompiliert und sagt "Der Standardparameterwert für 's' muss eine Konstante für die Kompilierungszeit sein. Die Antwort von OP funktioniert.
Wenn Sie Code visuell durchsuchen, wird "" so eingefärbt angezeigt, wie Zeichenfolgen eingefärbt sind. string.Empty sieht aus wie ein normaler Zugriff auf Klassenmitglieder. Während eines kurzen Blicks ist es einfacher, die Bedeutung zu erkennen oder zu verstehen.
Finde die Zeichenfolgen (die Stapelüberlauffärbung hilft nicht gerade, aber in VS ist dies offensichtlicher):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;
\u00ad
.
Alle hier gaben eine gute theoretische Erklärung. Ich hatte einen ähnlichen Zweifel. Also habe ich eine grundlegende Codierung versucht. Und ich habe einen Unterschied gefunden. Hier ist der Unterschied.
string str=null;
Console.WriteLine(str.Length); // Exception(NullRefernceException) for pointing to null reference.
string str = string.Empty;
Console.WriteLine(str.Length); // 0
Es scheint also, dass "Null" absolut nichtig bedeutet und "String.Empty" bedeutet, dass es einen Wert enthält, aber leer ist.
""
Versus handelt string.Empty
. Nur beim Versuch festzustellen, ob die Zeichenfolge leer ist, null
wurde erwähnt.
string.Empty
und was der Grund dafür war, es alsreadonly
statt zu deklarierenconst
.