Odpowiedzi:
W .NET wcześniejszej do wersji 2.0, ""
tworzy obiekt natomiast string.Empty
stwarza żadnego obiektu ref , co sprawia, że string.Empty
bardziej efektywne.
W wersji 2.0 i późniejszych .NET wszystkie wystąpienia ""
odnoszą się do tego samego literału łańcuchowego, co oznacza, że ""
jest równoważne .Empty
, ale wciąż nie tak szybkie jak .Length == 0
.
.Length == 0
jest najszybszą opcją, ale .Empty
zapewnia nieco czystszy kod.
Aby uzyskać więcej informacji, zobacz specyfikację platformy .NET .
string.IsNullOrEmpty( stringVar )
.
jaka jest różnica między String.Empty i "" i czy są one wymienne
string.Empty
jest polem tylko do odczytu, podczas gdy ""
jest stałą czasową kompilacji. Miejsca, w których zachowują się inaczej, to:
Domyślna wartość parametru w C # 4.0 lub wyższej
void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
//... implementation
}
Wyrażenie wielkości liter w instrukcji switch
string str = "";
switch(str)
{
case string.Empty: // Error: A constant value is expected.
break;
case "":
break;
}
Podaj argumenty
[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
w większości przypadków można przekazać argument jako argument Masz rację, że wszystkie przykłady to pokazują you simply can't put a (run-time) "value" into (compile-time) metadata
i właśnie to pokazują.
Poprzednie odpowiedzi były poprawne dla .NET 1.1 (spójrz na datę posta, do którego prowadzą link: 2003). Począwszy od wersji .NET 2.0 i nowszych, nie ma zasadniczo różnicy. W każdym razie JIT będzie odwoływał się do tego samego obiektu na stercie.
Zgodnie ze specyfikacją C #, sekcja 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx
Każdy literał ciągu niekoniecznie powoduje powstanie nowej instancji ciągu. Kiedy dwa lub więcej literałów łańcuchowych, które są równoważne zgodnie z operatorem równości łańcuchów (Rozdział 7.9.7), pojawiają się w tym samym zestawie, te literały łańcuchowe odnoszą się do tej samej instancji łańcucha.
Ktoś nawet wspomina o tym w komentarzach do postu Brada Abrama
Podsumowując, praktyczny wynik „” vs. String.Empty wynosi zero. JIT rozwiąże to na końcu.
Przekonałem się osobiście, że JIT jest znacznie mądrzejszy ode mnie, dlatego staram się nie być zbyt sprytny dzięki takim optymalizacjom mikrokompilatora. JIT będzie się rozwijał dla pętli (), usuwał zbędny kod, metody wbudowane itp. Lepiej i w bardziej odpowiednich momentach, niż ja lub kompilator C # mógł kiedykolwiek przewidzieć. Niech JIT wykona swoją pracę :)
String.Empty
jest polem tylko do odczytu, podczas gdy ""
jest stałą . Oznacza to, że nie można użyć String.Empty
instrukcji switch, ponieważ nie jest ona stałą.
default
słowa kluczowego możemy zwiększyć czytelność bez, zapobiegać przypadkowej modyfikacji i mieć stałą czasową kompilacji, choć szczerze mówiąc, nadal uważam, że String.Empty jest bardziej czytelny niż domyślny, ale wolniej pisać
Kolejna różnica polega na tym, że String.Empty generuje większy kod CIL. Chociaż kod do odwoływania się do „” i String.Empty ma tę samą długość, kompilator nie optymalizuje konkatenacji ciągów (patrz post na blogu Erica Lipperta ) pod kątem argumentów String.Empty. Następujące równoważne funkcje
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
wygeneruj tę 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")
Powyższe odpowiedzi są technicznie poprawne, ale to, czego możesz naprawdę chcieć użyć, dla najlepszej czytelności kodu i najmniejszej szansy na wyjątek to String.IsNullOrEmpty (s)
--foo=$BAR
, prawdopodobnie chcesz zauważyć różnicę między nimi, zapominając o ustawieniu zmiennej env a tym, że w ogóle nie przekazują flagi. string.IsNullOrEmpty
to często zapach kodu, który nie sprawdził poprawności danych wejściowych lub robi dziwne rzeczy. Zasadniczo nie powinieneś akceptować pustych ciągów, gdy naprawdę chcesz użyć null
lub czegoś w rodzaju typu Może / Opcja.
Zwykle używam String.Empty
raczej niż ""
z jednego prostego, ale nieoczywistego powodu:
""
i ""
NIE są takie same, pierwszy ma w rzeczywistości 16 znaków o zerowej szerokości. Oczywiście żaden kompetentny programista nie wstawi do kodu znaków o zerowej szerokości, ale jeśli się tam dostanie, może to być koszmar konserwacji.
Uwagi:
W tym przykładzie użyłem U + FEFF .
Nie jestem pewien, czy SO zamierza zjeść te postacie, ale spróbuj sam z jednym z wielu znaków o zerowej szerokości
Natknąłem się na to tylko dzięki https://codegolf.stackexchange.com/
Użyj String.Empty
raczej niż ""
.
Jest to więcej niż szybkość użycia pamięci, ale jest to przydatna wskazówka.
""
Jest dosłownym tak będzie działać jako dosłowna: od pierwszego użycia i jest on stworzony dla następujących zastosowań zwracana jest jego odniesienie. Tylko jedna instancja""
będzie przechowywana w pamięci bez względu na to, ile razy z niej korzystamy! Nie widzę tu żadnych kar za pamięć. Problem polega na tym, że przy każdym""
użyciu jest wykonywana pętla porównawcza, aby sprawdzić, czy""
jest już w puli wewnętrznej. Z drugiej stronyString.Empty
jest odniesieniem do""
przechowywanego w strefie pamięci .NET Framework .String.Empty
wskazuje ten sam adres pamięci dla aplikacji VB.NET i C #. Po co więc szukać referencji za każdym razem, gdy potrzebujesz ?""
gdy jest gdy ma się taką referencjęString.Empty
Odniesienie: String.Empty
vs""
String.Empty nie tworzy obiektu, podczas gdy „” robi. Różnica, jak wskazano tutaj , jest jednak banalna.
Wszystkie wystąpienia „” są takie same, dosłownie napisany ciąg znaków (lub powinny być). Więc naprawdę nie będziesz rzucał nowego obiektu na stos za każdym razem, gdy użyjesz „”, ale po prostu utworzysz odniesienie do tego samego, internowanego obiektu. Powiedziawszy to, wolę ciąg. Pusty. Myślę, że dzięki temu kod jest bardziej czytelny.
To po prostu nie ma znaczenia!
Niektóre wcześniejsze dyskusje na ten temat:
http://www.codinghorror.com/blog/archives/000185.html
string mystring = "";
ldstr ""
ldstr
wypycha odwołanie do nowego obiektu do literału ciągu zapisanego w metadanych.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
wypycha wartość pola statycznego na stos oceny
Zwykle używam String.Empty
zamiast tego, ""
ponieważ IMHO jest jaśniejsze i mniej VB.
Eric Lippert napisał (17 czerwca 2013 r.):
„Pierwszym algorytmem, nad którym pracowałem w kompilatorze C #, był optymalizator obsługujący konkatenacje ciągów. Niestety, nie udało mi się przenieść tych optymalizacji do bazy kodów Roslyn przed wyjazdem; mam nadzieję, że ktoś to zrobi dostać się do tego! ”
Oto niektóre wyniki Roslyn x64 ze stycznia 2019 r. Pomimo konsensusowych uwag innych odpowiedzi na tej stronie, nie wydaje mi się, aby obecny JIT x64 traktował wszystkie te przypadki identycznie, kiedy wszystko zostało powiedziane i zrobione.
Zauważ jednak w szczególności, że tylko jeden z tych przykładów w rzeczywistości kończy się wywołaniem String.Concat
i domyślam się, że dzieje się tak z niejasnych powodów poprawności (w przeciwieństwie do nadzoru nad optymalizacją). Inne różnice wydają się trudniejsze do wyjaśnienia.
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
Mówiąc o tym z punktu widzenia Entity Framework: wydaje się, że wersje EF 6.1.3 traktują String.Empty i "" inaczej podczas walidacji.
string.Empty jest traktowany jako wartość zerowa do celów sprawdzania poprawności i zgłosi błąd sprawdzania poprawności, jeśli zostanie użyty w polu Required (przypisanym); gdzie jako „” przejdzie sprawdzanie poprawności i nie zgłosi błędu.
Ten problem można rozwiązać w EF 7+. Odniesienie: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Edycja: [Wymagane (AllowEmptyStrings = true)] rozwiąże ten problem, umożliwiając sprawdzenie poprawności ciągu.Empty.
Ponieważ String.Empty nie jest stałą czasową kompilacji, nie można jej użyć jako wartości domyślnej w definicji funkcji.
public void test(int i=0,string s="")
{
// Function Body
}
public void test(int i=0, string s=string.Empty) {}
nie będzie się kompilować i powie „Domyślna wartość parametru dla 's' musi być stałą czasu kompilacji. Odpowiedź OP działa.
Gdy wizualnie skanujesz kod, „” jest pokolorowane w sposób pokolorowany. string.Empty wygląda jak zwykły dostęp do klasy. Podczas szybkiego spojrzenia łatwiej jest dostrzec „” lub zinterpretować znaczenie.
Znajdź łańcuchy (kolorystyka przepełnienia stosu nie pomaga, ale w VS jest to bardziej oczywiste):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;
\u00ad
.
Wszyscy tutaj udzielili dobrych teoretycznych wyjaśnień. Miałem podobne wątpliwości. Więc wypróbowałem na nim podstawowe kodowanie. I znalazłem różnicę. Oto różnica.
string str=null;
Console.WriteLine(str.Length); // Exception(NullRefernceException) for pointing to null reference.
string str = string.Empty;
Console.WriteLine(str.Length); // 0
Wydaje się więc, że „Null” oznacza absolutnie nieważne, a „String.Empty” oznacza Zawiera pewną wartość, ale jest pusta.
""
kontra string.Empty
. null
Wspomniano tylko o próbie stwierdzenia, czy ciąg znaków jest pusty .
string.Empty
i jakie było uzasadnienie zadeklarowania goreadonly
zamiastconst
.