Qual è la differenza tra String.Empty e & # 8220; & # 8221; (stringa vuota)?
-
02-07-2019 - |
Domanda
In .NET, qual è la differenza tra String.Empty
e " "
, e sono intercambiabili, o c'è qualche riferimento sottostante o problemi di localizzazione in giro uguaglianza che String.Empty
garantirà non essere un problema?
Soluzione
In .NET prima della versione 2.0, " "
crea un oggetto mentre string.Empty
non crea alcun oggetto ref , che rende string.Empty
altro efficiente.
Nella versione 2.0 e successive di .NET, tutte le occorrenze di " "
si riferiscono alla stessa stringa letterale, il che significa che " "
è equivalente a < code> .Empty , ma non ancora veloce come .Length == 0
.
.Length == 0
è l'opzione più veloce, ma .Empty
rende il codice leggermente più pulito.
Altri suggerimenti
qual è la differenza tra String.Empty e " " ;, e loro sono interchangable
string.Empty
è un campo di sola lettura mentre " "
è una costante di tempo di compilazione. I luoghi in cui si comportano diversamente sono:
Valore del parametro predefinito in C # 4.0 o versione successiva
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Espressione maiuscola nell'istruzione switch
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Argomenti degli attributi
[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type
Le risposte precedenti erano corrette per .NET 1.1 (guarda la data del post che hanno collegato: 2003). A partire da .NET 2.0 e versioni successive, non vi è sostanzialmente alcuna differenza. La JIT finirà comunque per fare riferimento allo stesso oggetto sull'heap.
Secondo la specifica C #, sezione 2.4.4.5: http://msdn.microsoft.com/en-us/ biblioteca / aa691090 (VS.71) aspx
Ogni stringa letterale non comporta necessariamente una nuova istanza di stringa. Quando due o più valori letterali di stringa equivalenti secondo l'operatore di uguaglianza di stringa (Sezione 7.9.7) compaiono nello stesso assieme, questi valori letterali di stringa fanno riferimento alla stessa istanza di stringa.
Qualcuno lo menziona persino nei commenti del post di Brad Abram
In breve, il risultato pratico di " " vs. String.Empty è zero. Il JIT lo capirà alla fine.
Ho scoperto, personalmente, che JIT è molto più intelligente di me e quindi cerco di non essere troppo intelligente con ottimizzazioni del micro-compilatore del genere. Il JIT si aprirà per () loop, rimuoverà il codice ridondante, i metodi inline, ecc. Meglio e in momenti più appropriati di quanto io o il compilatore C # potremmo mai anticipare prima. Lascia che JIT faccia il suo lavoro :)
String.Empty
è un campo di sola lettura mentre " "
è una const . Ciò significa che non è possibile utilizzare String.Empty
in un'istruzione switch perché non è una costante.
Un'altra differenza è che String.Empty genera un codice CIL più grande. Mentre il codice per fare riferimento a " " e String.Empty ha la stessa lunghezza, il compilatore non ottimizza la concatenazione di stringhe (vedi post di blog ) per argomenti String.Empty. Le seguenti funzioni equivalenti
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
genera questo 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
}
Le risposte di cui sopra sono tecnicamente corrette, ma ciò che potresti davvero voler usare, per la migliore leggibilità del codice e la minima possibilità di un'eccezione è String.IsNullOrEmpty (s)
Tendo a usare String.Empty
anziché " "
per un motivo semplice, ma non ovvio:
" & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; "
e " "
NON sono gli stessi, il primo contiene effettivamente 16 caratteri di larghezza zero. Ovviamente nessuno sviluppatore competente inserirà caratteri e larghezza zero nel loro codice, ma se entrano lì, può essere un incubo per la manutenzione.
Note:
-
Ho usato U + FEFF in questo esempio.
-
Non sono sicuro se SO mangerà quei personaggi, ma provalo tu stesso con uno dei tanti caratteri a larghezza zero
-
L'ho scoperto solo grazie a https://codegolf.stackexchange.com/
Usa String.Empty
anziché ""
.
Questo è più per la velocità rispetto all'utilizzo della memoria ma è un suggerimento utile. Il
" "
è un valore letterale, quindi agirà come un valore letterale: al primo utilizzo è creato e per i seguenti usi viene restituito il riferimento. Solo uno l'istanza di" "
verrà archiviata in memoria indipendentemente da quante volte usalo! Non vedo alcuna penalità di memoria qui. Il problema è quello ogni volta che si utilizza" "
, viene eseguito un ciclo di confronto per verificare se" "
è già nel pool interno. Dall'altro lato,String.Empty
è un riferimento a un" "
archiviato nella area di memoria di .NET Framework .String.Empty
punta allo stesso indirizzo di memoria per VB.NET e C # applicazioni. Quindi perché cercare un riferimento ogni volta che hai bisogno di" "
quando hai quel riferimento inString.Empty
?
Riferimento: String.Empty
vs " "
String.Empty non crea un oggetto mentre " " lo fa. La differenza, come sottolineato qui , è banale, tuttavia.
Non importa!
Alcune discussioni precedenti su questo:
http://www.codinghorror.com/blog/archives/000185.html
http://blogs.msdn.com/brada/ archive / 2003/04/22 / 49997.aspx
http://blogs.msdn.com/brada/ archive / 2003/04/27 / 50014.aspx
Tutte le istanze di " " sono le stesse stringhe letterali internate (o dovrebbero essere). Quindi non lancerai un nuovo oggetto sull'heap ogni volta che usi " " ma semplicemente creando un riferimento allo stesso oggetto internato. Detto questo, preferisco string.Empty. Penso che renda il codice più leggibile.
string mystring = "";
ldstr ""
ldstr
invia un nuovo riferimento all'oggetto a una stringa letterale memorizzata nei metadati.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
inserisce il valore di un campo statico nello stack di valutazione
Tendo a usare String.Empty
invece di " "
perché IMHO è più chiaro e meno VB-ish.
Da questo punto di vista dal punto di vista di Entity Framework: le versioni EF 6.1.3 sembrano trattare String.Empty e " " diversamente durante la convalida.
string.Empty viene trattato come un valore null ai fini della validazione e genererà un errore di validazione se viene utilizzato su un campo obbligatorio (attribuito); dove come " " passerà la convalida e non genererà l'errore.
Questo problema può essere risolto in EF 7+. Riferimento: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Modifica: [Obbligatorio (AllowEmptyStrings = true)] risolverà questo problema, consentendo la validazione di string.Empty.
Poiché String.Empty non è una costante di compilazione non è possibile utilizzarlo come valore predefinito nella definizione della funzione.
public void test(int i=0,string s="")
{
// Function Body
}
Eric Lippert ha scritto (17 giugno 2013):
" Il primo algoritmo su cui abbia mai lavorato nel compilatore C # è stato l'ottimizzatore che gestisce le concatenazioni di stringhe. Sfortunatamente non sono riuscito a portare queste ottimizzazioni sulla base di codice di Roslyn prima di partire; speriamo che qualcuno ci arrivi! "
Ecco alcuni risultati Roslyn x64 a gennaio 2019. Nonostante le osservazioni di consenso delle altre risposte in questa pagina, non mi sembra che l'attuale JIT x64 stia trattando tutti questi casi allo stesso modo, quando tutto è detto e fatto.
Nota in particolare, tuttavia, che solo uno di questi esempi finisce per chiamare String.Concat
, e suppongo che ciò sia per oscure ragioni di correttezza (al contrario di una svista di ottimizzazione). Le altre differenze sembrano più difficili da spiegare.
predefinito (stringa) & nbsp; + & nbsp; {default (String), & nbsp; " " ;, & nbsp; 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
" " & Nbsp; + & nbsp; {default (String), & nbsp; " " ;, & nbsp; 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 & nbsp; + & nbsp; {default (String), & nbsp; " " ;, & nbsp; 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
Dettagli del test
Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false
Quando esegui la scansione visiva del codice, " " appare colorato come sono colorate le stringhe. string.Empty sembra un normale accesso ai membri della classe. Durante una rapida occhiata, è più facile individuare " " o intuire il significato.
Trova le stringhe (la colorazione di overflow dello stack non aiuta esattamente, ma in VS questo è più ovvio):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;
Tutti qui hanno fornito alcuni buoni chiarimenti teorici. Avevo un dubbio simile. Quindi ho provato un codice di base su di esso. E ho trovato la differenza. Ecco la differenza.
string str=null;
Console.WriteLine(str.Length); // Exception(NullRefernceException) for pointing to null reference.
string str = string.Empty;
Console.WriteLine(str.Length); // 0
Quindi sembra " Null " significa assolutamente nullo & amp; & Quot; String.Empty " significa che contiene un qualche tipo di valore, ma è vuoto.