Risposte:
In .NET precedenti alla versione 2.0, ""
crea un oggetto mentre string.Empty
crea nessun oggetto ref , che rende string.Empty
più 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 .Empty
, ma ancora non così veloce .Length == 0
.
.Length == 0
è l'opzione più veloce, ma .Empty
rende il codice leggermente più pulito.
Vedere la specifica .NET per ulteriori informazioni .
string.IsNullOrEmpty( stringVar )
.
qual è la differenza tra String.Empty e "", e sono intercambiabili
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 successivo
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Espressione case nell'istruzione switch
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Argomenti dell'attributo
[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
nella maggior parte dei casi puoi passare come argomento. Hai ragione che tutti gli esempi lo dimostrano you simply can't put a (run-time) "value" into (compile-time) metadata
e questo è ciò che gli esempi mirano a mostrare.
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/library/aa691090(VS.71).aspx
Ogni stringa letterale non comporta necessariamente una nuova istanza di stringa. Quando due o più valori letterali di stringa equivalenti in base all'operatore di uguaglianza di stringa (Sezione 7.9.7) appaiono 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 sintesi, 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.
default
parola chiave possiamo promuovere la leggibilità senza, impedire modifiche accidentali e avere una costante di compilazione, anche se ad essere sincero, penso ancora String.Empty è più leggibile del valore predefinito, ma più lento da digitare
Un'altra differenza è che String.Empty genera un codice CIL più grande. Mentre il codice di riferimento "" e String.Empty ha la stessa lunghezza, il compilatore non ottimizza la concatenazione di stringhe (vedi il post sul blog di Eric Lippert ) per gli 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
}
"bar " + (ok ? "" : "error")
Le risposte 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)
--foo=$BAR
, probabilmente vorrai individuare la differenza tra loro dimenticando di impostare un var e senza passare la bandiera. string.IsNullOrEmpty
è spesso un odore di codice che non hai convalidato correttamente i tuoi input o stai facendo cose strane. Non dovresti generalmente accettare stringhe vuote quando intendi veramente usare null
, o qualcosa del tipo Forse / Opzione.
Tendo a usarlo String.Empty
piuttosto che ""
per un motivo semplice, ma non ovvio:
""
e ""
NON sono gli stessi, il primo in realtà ha 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.
Appunti:
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
piuttosto che ""
.
Questo è più per la velocità rispetto all'utilizzo della memoria ma è un suggerimento utile. Il
""
è un letterale, quindi agirà come un letterale: al primo utilizzo viene creato e per i seguenti usi viene restituito il riferimento. Solo un'istanza di""
verrà memorizzata, non importa quante volte la usiamo! Non vedo alcuna penalità di memoria qui. Il problema è che ogni volta che""
viene utilizzato, viene eseguito un ciclo di confronto per verificare se""
è già presente nel pool interno. D'altra parte,String.Empty
è un riferimento a un""
archiviato nell'area di memoria di .NET Framework .String.Empty
punta allo stesso indirizzo di memoria per le applicazioni VB.NET e C #. Quindi perché cercare un riferimento ogni volta che ti serve""
quando hai quel riferimentoString.Empty
?
Riferimento: String.Empty
vs""
String.Empty non crea un oggetto mentre "" lo fa. La differenza, come sottolineato qui , è comunque banale.
Tutte le istanze di "" sono le stesse, stringa internata letterale (o dovrebbero essere). Quindi non lancerai un nuovo oggetto sull'heap ogni volta che utilizzi "", ma semplicemente creando un riferimento allo stesso oggetto internato. Detto questo, preferisco string.Empty. Penso che renda il codice più leggibile.
Non importa!
Qualche discussione passata su questo:
http://www.codinghorror.com/blog/archives/000185.html
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 usarlo String.Empty
invece ""
perché IMHO è più chiaro e meno VB-ish.
Eric Lippert ha scritto (17 giugno 2013):
"Il primo algoritmo su cui ho mai lavorato nel compilatore C # era l'ottimizzatore che gestisce le concatenazioni di stringhe. Sfortunatamente non sono riuscito a trasferire queste ottimizzazioni sulla base di codice di Roslyn prima di partire; spero che qualcuno lo farà arrivare a quello! "
Ecco alcuni risultati di 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 in modo identico, 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.
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
Venendo a questo dal punto di vista di Entity Framework: le versioni EF 6.1.3 sembrano trattare String.Empty e "" in modo diverso durante la convalida.
string.Empty viene trattato come un valore null ai fini della convalida e genererà un errore di convalida se viene utilizzato in un campo obbligatorio (attribuito); dove "" passerà la convalida e non genera 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
}
public void test(int i=0, string s=string.Empty) {}
non compilerà e dirà "Il valore del parametro predefinito per 's' deve essere una costante di compilazione. La risposta di OP funziona.
Quando si esegue la scansione visiva del codice, "" appare colorato come le stringhe sono colorate. string.Empty sembra un normale accesso ai membri della classe. Durante una rapida occhiata, è più facile individuare "" o intuirne il significato.
Individua 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;
\u00ad
.
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 nulla e "String.Empty" significa che contiene un qualche tipo di valore, ma è vuoto.
""
versus string.Empty
. Solo quando si cerca di dire se la stringa è vuota, è null
stata menzionata.
string.Empty
e qual è stata la logica alla base della sua dichiarazionereadonly
anzichéconst
.