Apa perbedaan antara String.Empty dan "" (string kosong)?


288

Di .NET, apa perbedaan antara String.Emptydan "", dan apakah keduanya dapat dipertukarkan, atau adakah beberapa referensi mendasar atau masalah lokalisasi seputar kesetaraan yang String.Emptyakan memastikan tidak ada masalah?


2
Pertanyaan sebenarnya adalah TIDAK apa yang agak mengapa . Mengapa Microsoft muncul string.Emptydan apa alasan di balik menyatakannya sebagai readonlyganti const.
user1451111

Jawaban:


294

Di .NET sebelum versi 2.0, ""buat objek sambil string.Emptybuat tidak ada referensi objek , yang membuatnya string.Emptylebih efisien.

Dalam versi 2.0 dan yang lebih baru. NET, semua kemunculan ""merujuk ke string literal yang sama, yang artinya ""setara dengan .Empty, tetapi masih tidak secepat .Length == 0.

.Length == 0adalah pilihan tercepat, tetapi .Emptymenghasilkan kode yang sedikit lebih bersih.

Lihat spesifikasi .NET untuk informasi lebih lanjut .


91
"" Hanya akan membuat objek sekali karena string magang. Pada dasarnya pengorbanan kinerja adalah kacang - keterbacaan lebih penting.
Jon Skeet

12
Menarik bahwa meskipun pertanyaan mengatakan apa-apa tentang membandingkan string baik "" atau string.Empty untuk memeriksa string kosong, banyak orang tampaknya menafsirkan pertanyaan seperti itu ...
peSHIr

11
Saya akan berhati-hati dengan .Length == 0, karena dapat membuang pengecualian jika variabel string Anda nol. Namun jika Anda mengeceknya "", itu hanya akan mengembalikan false tanpa terkecuali.
Jeffrey Harmon

11
@ JeffreyHarmon: Atau Anda bisa menggunakan string.IsNullOrEmpty( stringVar ).
Flynn1179

1
Jika ada yang ingin mencegah praktik buruk untuk menguji string kosong, Anda dapat mengaktifkan CA1820 dalam Analisis Kode. docs.microsoft.com/visualstudio/code-quality/…
sean

197

apa perbedaan antara String.Empty dan "", dan apakah keduanya dapat dipertukarkan

string.Emptyadalah bidang baca-saja sedangkan ""konstanta waktu kompilasi. Tempat-tempat di mana mereka berperilaku berbeda adalah:

Nilai Parameter default dalam C # 4.0 atau lebih tinggi

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

Ekspresi huruf dalam pernyataan sakelar

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

    case "":
        break;

}

Argumen atribut

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

21
Menarik, saya tidak berpikir pertanyaan lama ini akan mendapatkan informasi baru yang relevan. Saya salah
johnc

Saya pikir contoh Anda # 1 Nilai Parameter Default di C # 4.0 atau lebih tinggi pada dasarnya adalah duplikat dari contoh Anda # 3 argumen Atribut , karena saya percaya bahwa .NET menyebarkan parameter default ke atribut. Jadi pada dasarnya, Anda tidak bisa memasukkan "nilai" (waktu berjalan) (dalam hal ini, pegangan instance , untuk stickler di luar sana) ke dalam metadata (waktu kompilasi).
Glenn Slayden

@ GlennSlayden, saya tidak setuju dengan Anda. Inisialisasi atribut berbeda dari inisialisasi biasa. Itu karena Anda dapat menyampaikan String.Emptyargumen dalam kebanyakan kasus. Anda benar bahwa semua contoh menunjukkan itu you simply can't put a (run-time) "value" into (compile-time) metadatadan itulah yang ingin ditunjukkan oleh contoh tersebut.
Sasuke Uchiha

42

Jawaban sebelumnya benar untuk .NET 1.1 (lihat tanggal posting yang mereka tautkan: 2003). Pada. NET 2.0 dan yang lebih baru, pada dasarnya tidak ada perbedaan. JIT pada akhirnya akan merujuk objek yang sama pada heap.

Menurut spesifikasi C #, bagian 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx

Setiap string literal tidak harus menghasilkan instance string baru. Ketika dua atau lebih liter string yang setara menurut operator kesetaraan string (Bagian 7.9.7) muncul dalam rakitan yang sama, literal string ini merujuk ke instance string yang sama.

Seseorang bahkan menyebutkan ini dalam komentar dari posting Brad Abram

Singkatnya, hasil praktis dari "" vs. String.Empty adalah nol. JIT akan mencari tahu pada akhirnya.

Saya telah menemukan, secara pribadi, bahwa JIT jauh lebih pintar daripada saya dan jadi saya mencoba untuk tidak terlalu pintar dengan optimasi mikro-kompiler seperti itu. JIT akan terbuka untuk () loop, menghapus kode redundan, metode inline, dll lebih baik dan pada waktu yang lebih tepat daripada yang saya atau kompiler C # bisa antisipasi sebelumnya. Biarkan JIT melakukan tugasnya :)


1
Kesalahan ketik kecil? "JIT akhirnya akan merujuk objek yang sama pada bantuan." Apakah maksud Anda "di tumpukan"?
Dana


36

String.Emptyadalah readonly bidang sementara ""adalah const . Ini berarti Anda tidak dapat menggunakan String.Emptypernyataan switch karena itu bukan konstanta.


dengan munculnya defaultkata kunci kita dapat mempromosikan keterbacaan tanpa, mencegah modifikasi yang tidak disengaja, dan memiliki waktu kompilasi yang konstan, meskipun jujur ​​saja, saya masih berpikir String.Empty lebih mudah dibaca daripada default, tetapi lebih lambat untuk mengetik
Enzoaeneas

18

Perbedaan lainnya adalah bahwa String.Empty menghasilkan kode CIL yang lebih besar. Sementara kode untuk referensi "" dan String.Empty memiliki panjang yang sama, kompiler tidak mengoptimalkan penggabungan string (lihat posting blog Eric Lippert ) untuk argumen String.Empty. Fungsi setara berikut

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

buat IL ini

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

Poin yang benar tetapi siapa yang akan melakukan hal seperti itu? Mengapa saya harus menyatukan string kosong dengan sesuatu dengan sengaja?
Robert S.

@RobertS. Mungkin string kedua berada di fungsi terpisah yang mendapat inline. Jarang, saya beri Anda.
Bruno Martinez

3
tidak jarang menggunakan operator ternary:"bar " + (ok ? "" : "error")
symbiont

13

Jawaban di atas secara teknis benar, tetapi apa yang mungkin Anda benar-benar ingin gunakan, untuk pembacaan kode terbaik dan peluang pengecualian terkecil adalah String.IsNullOrEmpty (s)


3
Dalam hal perbandingan kesetaraan, saya sepenuhnya setuju, tetapi pertanyaannya juga tentang perbedaan antara kedua konsep serta perbandingan
johnc

1
Waspadalah bahwa "peluang perkecualian" paling sering berarti "sebagian besar peluang untuk melanjutkan tetapi melakukan sesuatu yang salah". Misalnya, jika Anda memiliki argumen baris perintah yang Anda parsing dan seseorang memanggil aplikasi --foo=$BARAnda, maka Anda mungkin ingin melihat perbedaan di antara mereka lupa mengatur env var dan mereka tidak melewati flag sama sekali. string.IsNullOrEmptysering merupakan bau kode yang Anda belum memvalidasi input Anda dengan benar atau melakukan hal-hal aneh. Anda biasanya tidak boleh menerima string kosong ketika Anda benar-benar bermaksud menggunakan null, atau sesuatu seperti tipe Maybe / Option.
Alastair Maw

11

Saya cenderung menggunakan String.Emptydaripada ""untuk satu alasan sederhana, namun tidak jelas: ""dan ""TIDAK sama, yang pertama sebenarnya memiliki 16 karakter lebar nol di dalamnya. Jelas tidak ada pengembang yang kompeten yang akan menempatkan dan nol karakter lebar ke dalam kode mereka, tetapi jika mereka masuk ke sana, itu bisa menjadi mimpi buruk pemeliharaan.

Catatan:

  • Saya menggunakan U + FEFF dalam contoh ini.

  • Tidak yakin apakah SO akan memakan karakter-karakter itu, tetapi cobalah sendiri dengan salah satu dari banyak karakter lebar nol

  • Saya hanya menemukan ini berkat https://codegolf.stackexchange.com/


Ini layak mendapatkan lebih banyak upvotes. Saya telah melihat masalah ini terjadi melalui integrasi sistem di seluruh platform.
EvilDr

8

Gunakan String.Emptydaripada "".

Ini lebih untuk kecepatan daripada penggunaan memori tetapi ini adalah tip yang berguna. Ini ""adalah literal sehingga akan bertindak sebagai literal: pada penggunaan pertama itu dibuat dan untuk penggunaan berikut referensi dikembalikan. Hanya satu instance dari yang ""akan disimpan dalam memori tidak peduli berapa kali kita menggunakannya! Saya tidak melihat hukuman memori di sini. Masalahnya adalah bahwa setiap kali ""digunakan, loop pembanding dijalankan untuk memeriksa apakah ""sudah ada di kolam intern. Di sisi lain, String.Empty adalah referensi ke ""tersimpan di zona memori .NET Framework . String.Emptymenunjuk ke alamat memori yang sama untuk aplikasi VB.NET dan C #. Jadi mengapa mencari referensi setiap kali Anda membutuhkannya "" ketika Anda memiliki referensi ituString.Empty?

Referensi: String.Emptyvs.""


2
Ini tidak benar sejak .net 2.0
nelsontruran

6

String.Empty tidak membuat objek sedangkan "" melakukannya. Perbedaannya, seperti yang ditunjukkan di sini , adalah sepele.


4
Itu tidak sepele jika Anda memeriksa string untuk string. Cukup atau "". Orang harus benar-benar menggunakan String.IsNullOrEmpty seperti yang ditunjukkan Eugene Katz. Kalau tidak, Anda akan mendapatkan hasil yang tidak terduga.
Sigur

6

Semua contoh "" adalah string literal yang diinternir sama (atau seharusnya). Jadi Anda benar-benar tidak akan melemparkan objek baru di heap setiap kali Anda menggunakan "" tetapi hanya membuat referensi ke objek yang sama, diinternir. Karena itu, saya lebih suka string.Empty. Saya pikir itu membuat kode lebih mudah dibaca.



4
string mystring = "";
ldstr ""

ldstr mendorong referensi objek baru ke string literal yang disimpan dalam metadata.

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

ldsfld mendorong nilai bidang statis ke tumpukan evaluasi

Saya cenderung menggunakan String.Emptybukan ""karena IMHO itu lebih jelas dan kurang VB-ish.


3

Eric Lippert menulis (17 Juni 2013):
"Algoritma pertama yang pernah saya kerjakan dalam kompiler C # adalah pengoptimal yang menangani penggabungan string. Sayangnya saya tidak berhasil mem-porting optimasi ini ke basis kode Roslyn sebelum saya pergi; semoga seseorang akan dapatkan itu! "

Berikut adalah beberapa hasil Roslyn x64 per Januari 2019. Meskipun pernyataan konsensus dari jawaban lain di halaman ini, tampaknya bagi saya bahwa JIT x64 saat ini memperlakukan semua kasus ini secara identik, ketika semua dikatakan dan dilakukan.

Perhatikan secara khusus, bagaimanapun, bahwa hanya satu dari contoh ini yang benar-benar berakhir dengan panggilan String.Concat, dan saya menduga itu karena alasan kebenaran yang tidak jelas (sebagai lawan dari pengawasan optimasi). Perbedaan lain tampaknya lebih sulit untuk dijelaskan.


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


Detail tes

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

2

Datang dari sudut pandang Entity Framework: EF versi 6.1.3 tampaknya memperlakukan String.Empty dan "" secara berbeda saat memvalidasi.

string.Empty diperlakukan sebagai nilai nol untuk keperluan validasi dan akan melempar kesalahan validasi jika digunakan pada bidang Diperlukan (dikaitkan); dimana "" akan melewati validasi dan tidak membuang kesalahan.

Masalah ini dapat diatasi dalam EF 7+. Referensi: - https://github.com/aspnet/EntityFramework/issues/2610 ).

Sunting: [Diperlukan (AllowEmptyStrings = true)] akan menyelesaikan masalah ini, memungkinkan string.Empty untuk memvalidasi.


2

Karena String.Empty bukan konstanta waktu kompilasi, Anda tidak dapat menggunakannya sebagai nilai default dalam definisi fungsi.

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

1
Hanya ringkasan dari jawaban ini: public void test(int i=0, string s=string.Empty) {}tidak akan mengkompilasi dan mengatakan "Nilai parameter default untuk 's' harus berupa konstanta waktu kompilasi. Jawaban OP berfungsi.
bugybunny

1

Saat Anda memindai kode secara visual, "" tampak berwarna seperti string yang diwarnai. string.Empty tampak seperti akses anggota kelas biasa. Selama tampilan cepat, lebih mudah menemukan "" atau intuisi maknanya.

Temukan string (stack overflow colorization tidak membantu, tetapi dalam VS ini lebih jelas):

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

2
Anda membuat poin yang bagus, tetapi apakah pengembang benar-benar bermaksud ""? Mungkin mereka bermaksud untuk memasukkan nilai yang belum diketahui dan lupa untuk kembali? string.Empty memiliki keuntungan memberi Anda keyakinan bahwa penulis asli benar-benar berarti string.Empty. Ini hal kecil yang saya tahu.
mark_h

Juga, pengembang jahat (atau ceroboh) dapat menempatkan karakter lebar nol di antara tanda kutip alih-alih menggunakan urutan melarikan diri yang sesuai seperti \u00ad.
Palec

-8

Semua orang di sini memberikan klarifikasi teoretis yang baik. Saya memiliki keraguan yang sama. Jadi saya mencoba coding dasar di atasnya. Dan saya menemukan perbedaan. Inilah bedanya.

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


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

Jadi sepertinya "Null" berarti benar-benar batal & "String.Empty" berarti Ini berisi semacam nilai, tetapi itu kosong.


7
Perhatikan bahwa pertanyaannya adalah tentang ""versus string.Empty. Hanya ketika mencoba untuk mengetahui apakah string kosong, nulltelah disebutkan.
Palec
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.