String.Empty ve “” (boş dize) arasındaki fark nedir?


288

.NET'te String.Emptyve arasındaki fark nedir ""ve bunlar birbirinin yerine kullanılabilir mi veya eşitlik konusunda String.Emptysorun olmamasını sağlayacak temel referans veya Yerelleştirme sorunları var mı?


2
Asıl soru DEĞİLDİR neyi ziyade neden . Microsoft neden ortaya çıktı string.Emptyve readonlybunun yerine ilan etmenin ardındaki mantık neydi const?
user1451111

Yanıtlar:


295

.NET 2.0 sürümünden önce ""bir nesne string.Emptyoluşturur, hiçbir nesne ref oluşturur , bu da string.Emptydaha verimli hale getirir .

.NET'in 2.0 ve sonraki sürümlerinde, tüm başvurular ""aynı dizgi değişmezine başvurur, yani ""eşdeğerdir .Empty, ancak yine de o kadar hızlı değildir .Length == 0.

.Length == 0 en hızlı seçenektir, ancak .Empty biraz daha temiz kod sağlar.

Daha fazla bilgi için .NET spesifikasyonuna bakın .


91
"", dize stajı nedeniyle zaten yalnızca bir kez bir nesne oluşturur. Temel olarak performans dengelemesi yer fıstığıdır - okunabilirlik daha önemlidir.
Jon Skeet

12
Sorusu boş katarları kontrol etmek ya "" veya String.Empty bir dize karşılaştırma hakkında bir şey söylüyor olsa bile, pek çok insan görünüyor ilginç soruyu yorumlamak bu şekilde ...
peSHIr

11
Eğer dize değişkeni null ise bir istisna atabilir gibi .Length == 0 dikkatli olun. Eğer "" ile karşılaştırırsanız, istisnasız düzgün şekilde yanlış döndürür.
Jeffrey Harmon

11
@JeffreyHarmon: Ya da kullanabilirsiniz string.IsNullOrEmpty( stringVar ).
Flynn1179

1
Herkes boş bir dizeyi sınamak için kötü uygulamaların önüne geçmek istiyorsa, CA1820'yi Kod Analizi'nde etkinleştirebilirsiniz. docs.microsoft.com/visualstudio/code-quality/…
sean

197

String.Empty ve "" arasındaki fark nedir ve bunlar değiştirilebilir mi?

string.Emptybir salt okunur alandır "", bir derleme zaman sabitidir. Farklı davrandıkları yerler:

C # 4.0 veya üzeri varsayılan parametre değeri

void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
    //... implementation
}

Switch deyiminde vaka ifadesi

string str = "";
switch(str)
{
    case string.Empty: // Error: A constant value is expected. 
        break;

    case "":
        break;

}

Özellik bağımsız değişkenleri

[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression 
//        or array creation expression of an attribute parameter type

21
İlginçtir, bu eski sorunun herhangi bir yeni bilgi alacağını düşünmüyordum. Yanılmışım
JohnC

Ben senin örnek # 1 C # 4.0 veya daha yüksek varsayılan parametre değeri aslında # 3 Öznitelik argümanlarının bir kopyası olduğunu düşünüyorum, çünkü .NET varsayılan parametreleri özniteliklere dağıtır inanıyorum. Daha temelde, (çalışma zamanı) "değer" (bu durumda, dışarıdaki etiketleyiciler için bir örnek tanıtıcısı ) meta verisine koyamazsınız.
Glenn Slayden

@GlennSlayden, sana katılmıyorum. Öznitelik başlatma, sıradan başlatmadan farklıdır. Çünkü String.Emptybir çok argümanı argüman olarak iletebilirsiniz . Tüm örneklerin bunu gösterdiği konusunda haklısınız ve örneklerin göstermeyi you simply can't put a (run-time) "value" into (compile-time) metadataamaçladığı şey bu.
Sasuke Uchiha

42

Önceki yanıtlar .NET 1.1 için doğruydu (bağlandıkları gönderinin tarihine bakın: 2003). .NET 2.0 ve sonraki sürümler itibariyle, aslında hiçbir fark yoktur. JIT yine de aynı nesneyi yığın üzerinde referans gösterecektir.

C # spesifikasyonuna göre, bölüm 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx

Her dize değişmezi mutlaka yeni bir dize örneği ile sonuçlanmaz. Dize eşitliği operatörüne (Bölüm 7.9.7) göre eşdeğer olan iki veya daha fazla dize değişmezi aynı derlemede göründüğünde, bu dize değişmezleri aynı dize örneğini ifade eder.

Birisi Brad Abram'ın gönderisinin yorumlarında bile bundan bahsediyor

Özetle, "" ve String.Empty arasındaki pratik sonuç sıfırdır. JIT sonunda çözecek.

Şahsen, JIT'in benden çok daha akıllı olduğunu gördüm ve bu yüzden böyle mikro derleyici optimizasyonlarıyla çok zeki olmamaya çalışıyorum. JIT, () döngüler için açılır, yedek kod, satır içi yöntemler, vb. Kaldırılır. I veya C # derleyicisinin önceden tahmin edebileceğinden daha iyi ve daha uygun zamanlarda. JIT işini yapsın :)


1
Küçük yazım hatası mı? "JIT yine de yardımda aynı nesneyi referans alacak." Şunu mu demek istediniz: "on the heap"?
Dana


36

String.EmptyBir olan salt okunur iken alan ""bir olduğunu const . Bu String.Empty, sabit olmadığı için bir switch deyiminde kullanamayacağınız anlamına gelir .


defaultAnahtar kelimenin ortaya çıkmasıyla, okunabilirliği teşvik etmeden, yanlışlıkla değişiklik yapılmasını önleyebileceğimiz ve derleme zamanı sabitine sahip olduğumuzdan, dürüst olmakla birlikte, hala
String.Empty'nin

18

Diğer bir fark ise String.Empty'nin daha büyük CIL kodu üretmesidir. "" Ve String.Empty'ye başvurma kodu aynı uzunlukta olsa da, derleyici String.Empty bağımsız değişkenleri için dize birleştirmeyi optimize etmez (bkz. Eric Lippert'in blog yazısı ). Aşağıdaki eşdeğer işlevler

string foo()
{
    return "foo" + "";
}
string bar()
{
    return "bar" + string.Empty;
}

bu IL'yi oluştur

.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 
}

Geçerli nokta ama böyle bir şeyi kim yapar? Neden boş bir dizeyi bilerek bir şeyle birleştirmeliyim?
Robert S.

@RobertS. Belki ikinci dize satır içine alınan ayrı bir işlevdeydi. Bu nadir, sana veriyorum.
Bruno Martinez

3
üçlü operatörü kullanmak o kadar nadir değildir:"bar " + (ok ? "" : "error")
symbiont

13

Yukarıdaki cevaplar teknik olarak doğrudur, ancak en iyi kod okunabilirliği ve en az istisna olasılığı için gerçekten kullanmak isteyebileceğiniz şey String'dir.


3
Eşitlik karşılaştırması açısından, tamamen katılıyorum, ancak soru aynı zamanda iki kavram arasındaki farkla da karşılaştırıldı
johnc

1
"En az istisna şansı" genellikle "devam etme ama yanlış bir şey yapma şansı" anlamına gelir. Örneğin, ayrıştırdığınız bir komut satırı argümanınız varsa ve birileri uygulamanızı çağırıyorsa, --foo=$BARmuhtemelen bir env var ayarlamayı unutan ve bayrağı hiç geçirmeyen aralarındaki farkı tespit etmek istersiniz. string.IsNullOrEmptygirdilerinizi doğru bir şekilde doğrulamadığınız veya garip şeyler yaptığınız bir kod kokusudur. Gerçekten kullanmak istediğinizde boş dizeleri nullveya Belki / Seçenek türü gibi bir şeyi kabul etmemelisiniz .
Alastair Maw

11

Basit ama açık olmayan bir sebepten String.Emptyziyade kullanma eğilimindeyim "": ""ve"" aynı DEĞİL, ilki aslında 16 sıfır genişlikli karakter içeriyor. Açıkçası, hiçbir yetkili geliştirici kodlarına sıfır genişlikli karakterler koyamaz, ancak içeri girerse, bir bakım kabusu olabilir.

Notlar:


Bu daha fazla oyu hak ediyor. Bu sorunun platformlar arasında sistem entegrasyonu ile oluştuğunu gördüm.
EvilDr

8

Bunun String.Emptyyerine kullanın "".

Bu, hız için bellek kullanımından daha fazlasıdır, ancak yararlı bir ipucudur. Bu ""bir değişmezdir, böylece değişmez bir işlev görür: ilk kullanımda oluşturulur ve aşağıdaki kullanımlar için başvurusu döndürülür. ""Kaç kez kullanırsak kullanalım , yalnızca bir örneği bellekte saklanır! Burada herhangi bir hafıza cezası görmüyorum. Sorun, her ""kullanıldığında, ""stajyer havuzunda olup olmadığını kontrol etmek için bir karşılaştırma döngüsü yürütülmesi . Diğer tarafta, .NET Framework bellek bölgesinde depolanan String.Empty bir başvurudır . VB.NET ve C # uygulamaları için aynı bellek adresini gösteriyor. Öyleyse neden her ihtiyacınız olduğunda bir referans aramalısınız ?""String.Empty"" bu referansa sahip olduğunuzda olduğundaString.Empty

Referans: String.Emptyvs""


2
.Net 2.0
nelsontruran

6

String.Empty bir nesne oluşturmazken "" oluşturur. Bununla birlikte, burada belirtildiği gibi, fark önemsizdir.


4
Bir dizeyi string için kontrol etmeniz önemsiz değildir. Boş veya "". Eugene Katz'ın işaret ettiği gibi String.IsNullOrEmpty'yi gerçekten kullanmalı. Aksi takdirde beklenmedik sonuçlar alırsınız.
Sigur

6

Tüm "" örnekleri aynı, sabit dize değişmezidir (veya olmalıdır). Yani "" her kullanışınızda öbek üzerine gerçekten yeni bir nesne fırlatmayacaksınız, ama aynı, interned nesneye bir referans oluşturacaksınız. Bunu söyledikten sonra string.Empty'yi tercih ederim. Kodun daha okunaklı olduğunu düşünüyorum.



4
string mystring = "";
ldstr ""

ldstr meta verilerde saklanan dize değişmezine yeni bir nesne başvurusu gönderir.

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld statik bir alanın değerini değerlendirme yığınına iter

Bunun String.Emptyyerine kullanma eğilimindeyim ""çünkü IMHO daha net ve daha az VB-ish.


3

Eric Lippert (17 Haziran 2013) şöyle yazdı :
"C # derleyicisinde çalıştığım ilk algoritma, dize birleştirme işlemlerini gerçekleştiren optimize ediciydi. Maalesef bu optimizasyonları gitmeden önce Roslyn kod tabanına aktarmayı başaramadım; umarım birisi alın bunu! "

İşte Ocak 2019 itibariyle bazı Roslyn x64 sonuçları. Bu sayfadaki diğer cevapların fikir birliği notlarına rağmen, mevcut x64 JIT'in, her şey söylendiğinde ve yapıldığında, bu vakaların tümüne aynı şekilde davrandığı görülmüyor.

Bununla birlikte, özellikle, bu örneklerden sadece birinin çağrıldığına dikkat edin String.Concatve bunun yanlış doğruluk nedenlerinden (optimizasyon gözetiminin aksine) tahmin ediyorum. Diğer farklılıkları açıklamak daha zor görünüyor.


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


Test ayrıntıları

Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false

2

Bir Entity Framework bakış açısından geliyor: EF 6.1.3 sürümü, String.Empty ve "" değerlerini doğrularken farklı davranıyor gibi görünüyor.

string.Empty, doğrulama amacıyla boş bir değer olarak değerlendirilir ve Zorunlu (ilişkilendirilmiş) bir alanda kullanılıyorsa bir doğrulama hatası atar; burada "" doğrulamayı geçecek ve hatayı atmayacaktır.

Bu sorun EF 7 ve sonraki sürümlerinde çözülebilir. Referans: - https://github.com/aspnet/EntityFramework/issues/2610 ).

Düzenleme: [Gerekli (AllowEmptyStrings = true)], dize.Empty'nin doğrulanmasına izin vererek bu sorunu çözecektir.


2

String.Empty bir derleme zamanı sabiti olmadığından, işlev tanımında varsayılan değer olarak kullanamazsınız.

public void test(int i=0,string s="")
    {
      // Function Body
    }

1
Sadece bu cevabın özeti public void test(int i=0, string s=string.Empty) {}derlenmeyecek ve "'s' için varsayılan parametre değeri derleme zamanı sabiti olmalıdır. OP'nin cevabı işe
yarar

1

Kod aracılığıyla görsel olarak tarama yaparken, dizelerin renklendirilme şekli renklendirilmiş olarak görünür. string.Empty normal bir sınıf-üye-erişimi gibi görünüyor. Hızlı bir bakış sırasında, anlamı "" bulmak veya sezmek daha kolaydır.

Dizeleri tespit edin (yığın taşması renklendirmesi tam olarak yardımcı olmaz, ancak VS'de bu daha açıktır):

var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

2
İyi bir noktaya değindin, ama geliştirici gerçekten "" demek mi? Belki de henüz bilinmeyen bir değer koyup geri dönmeyi unuttular? string.Empty, orijinal yazarın gerçekten string anlamına geldiğine dair güven verme avantajına sahiptir. Bu küçük bir nokta biliyorum.
mark_h

Ayrıca, kötü niyetli (veya dikkatsiz) bir geliştirici, uygun kaçış dizisini kullanmak yerine tırnak işaretleri arasına sıfır genişlikli bir karakter koyabilir \u00ad.
Palec

-8

Buradaki herkes iyi bir teorik açıklama yaptı. Benzer bir şüphem vardı. Bu yüzden üzerinde temel bir kodlama denedim. Ve bir fark buldum. Fark burada.

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference. 


string str = string.Empty;
Console.WriteLine(str.Length);  // 0

Bu yüzden "Null" kesinlikle geçersiz anlamına gelir & "String.Empty", bir tür değer içerdiği anlamına gelir, ancak boştur.


7
Soru hakkında olduğunu unutmayın ""karşı string.Empty. Sadece ipin boş olup olmadığını söylemeye çalışırken nullbahsedilmişti.
Palec
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.