Perbedaan dalam metode perbandingan string dalam C #

261

Membandingkan string dalam C # cukup sederhana. Sebenarnya ada beberapa cara untuk melakukannya. Saya telah mendaftarkan beberapa di blok di bawah ini. Apa yang saya ingin tahu tentang perbedaan antara mereka dan kapan satu harus digunakan atas yang lain Haruskah seseorang dihindari dengan cara apa pun? Apakah ada lagi yang belum saya daftarkan?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(Catatan: Saya mencari persamaan dalam contoh ini, tidak kurang dari atau lebih besar dari tetapi merasa bebas untuk mengomentari itu juga)

Craig
sumber
4
Satu perangkap adalah Anda tidak dapat melakukan stringValue.Equals (null) karena itu mengasumsikan Anda dapat memanggil metode pada null
johnc
1
Referensi MSDN
Robert Harvey
@RobertHarvey Alasan saya datang ke stackoverflow adalah agar saya tidak perlu membaca beberapa halaman untuk mendapatkan jawaban.
Syaiful Nizam Yahya
@Syaiful: Alasan saya datang ke Stack Overflow adalah untuk menemukan jawaban yang tidak ada dalam dokumentasi.
Robert Harvey

Jawaban:

231

Berikut adalah aturan untuk cara kerja fungsi-fungsi ini:

stringValue.CompareTo(otherStringValue)

  1. null datang sebelum string
  2. ia menggunakan CultureInfo.CurrentCulture.CompareInfo.Compare, yang berarti akan menggunakan perbandingan yang bergantung pada budaya. Ini mungkin berarti bahwa ßakan membandingkan sama dengan SSdi Jerman, atau serupa

stringValue.Equals(otherStringValue)

  1. null tidak dianggap sama dengan apa pun
  2. kecuali jika Anda menentukan StringComparisonopsi, itu akan menggunakan apa yang tampak seperti pemeriksaan kesetaraan ordinal langsung, yaitu ßtidak sama dengan SS, dalam bahasa atau budaya apa pun

stringValue == otherStringValue

  1. Tidak sama dengan stringValue.Equals().
  2. The ==Operator menyebut statis Equals(string a, string b)metode (yang pada gilirannya pergi ke internal EqualsHelperuntuk melakukan perbandingan.
  3. Memanggil .Equals()pada nullstring yang mendapat nullreferensi pengecualian, sementara di ==tidak.

Object.ReferenceEquals(stringValue, otherStringValue)

Hanya memeriksa referensi yang sama, yaitu bukan hanya dua string dengan konten yang sama, Anda membandingkan objek string dengan dirinya sendiri.


Perhatikan bahwa dengan opsi di atas yang menggunakan pemanggilan metode, ada kelebihan dengan lebih banyak opsi untuk menentukan cara membandingkan.

Saran saya jika Anda hanya ingin memeriksa kesetaraan adalah memutuskan apakah Anda ingin menggunakan perbandingan yang bergantung pada budaya atau tidak, dan kemudian menggunakan .CompareToatau .Equals, tergantung pada pilihan.

Lasse V. Karlsen
sumber
5
"stringValue.Equals (otherStringValue): null tidak sama dengan null" Lol, saya katakan tidak. null sama dengan pengecualian ObjectReferenceNotSet.
Kevin
29
== tidak sama dengan .Equals () ... Operator == memanggil metode Equals statis (string a, string b) (yang pada gilirannya pergi ke EqualsHelper internal untuk melakukan perbandingan. Memanggil. Sama dengan nol string mendapat null referensi exc., sedangkan pada == tidak.
Dan C.
2
Di sisi lain, .Equals sedikit lebih cepat (satu metode panggilan lebih sedikit secara internal), tetapi kurang dapat dibaca - tentu saja :).
Dan C.
Saya berpikir '==' akan melakukan perbandingan referensi dan object.equals akan melakukan perbandingan nilai. Bagaimana '==' dan string.equals bekerja sama?
amesh
@ LasseV.Karlsen Apa pendapat Anda String.Compare?
JDandChips
72

Dari MSDN:

"Metode CompareTo dirancang terutama untuk digunakan dalam operasi penyortiran atau alfabetisasi. Metode ini tidak boleh digunakan ketika tujuan utama pemanggilan metode adalah untuk menentukan apakah dua string setara. Untuk menentukan apakah dua string setara, hubungi metode Persamaan. "

Mereka menyarankan menggunakan .Equalsalih-alih .CompareToketika hanya mencari kesetaraan. Saya tidak yakin apakah ada perbedaan antara .Equalsdan ==untuk stringkelas. Saya kadang-kadang akan menggunakan .Equalsatau Object.ReferenceEqualsbukan ==untuk kelas saya sendiri jika seseorang datang di lain waktu dan mendefinisikan kembali ==operator untuk kelas itu.

Ed S.
sumber
18
Apakah itu pernah terjadi pada Anda? (Mendefinisikan ulang ==) ... Saya melihatnya sebagai waaaay pemrograman terlalu defensif =)
juan
Ya, itu sebabnya saya sekarang menggunakan Object.ReferenceEquals ketika saya mencari persamaan objek :). Ini mungkin sedikit terlalu defensif, tetapi saya tidak gila tentang hal itu dan sejujurnya situasi ini tidak sering muncul.
Ed S.
Saya ragu bahwa 'defensive coding' ini berguna. Bagaimana jika pemilik kelas perlu mengganti operator ==, kemudian mengetahui tidak ada yang menggunakannya?
Dave Van den Eynde
1
@DaveVandenEynde: Ya ... saya menulis ini beberapa waktu lalu. Saya tidak melakukan ini secara teratur, hanya mengesampingkan. Sama bila sesuai.
Ed S.
1
Rekomendasi Microsoft dicatat di sini: Praktik Terbaik untuk Menggunakan String dalam .NET Framework
JJS
50

Jika Anda ingin tahu tentang perbedaan dalam metode BCL, Reflector adalah teman Anda :-)

Saya mengikuti panduan ini:

Pencocokan tepat: EDIT: Saya sebelumnya selalu menggunakan operator == pada prinsip bahwa di dalam Persamaan (string, string) objek == operator digunakan untuk membandingkan referensi objek tetapi tampaknya strA.Equals (strB) masih 1-11% keseluruhan lebih cepat dari string.Equals (strA, strB), strA == strB, dan string.CompareOrdinal (strA, strB). I loop diuji dengan StopWatch pada nilai string yang diinternir / tidak diinternir, dengan panjang string yang sama / berbeda, dan berbagai ukuran (1B hingga 5MB).

strA.Equals(strB)

Pencocokan yang bisa dibaca manusia (budaya Barat, tidak sensitif huruf besar):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Kecocokan yang dapat dibaca manusia (Semua budaya lain, huruf / aksen / kana / dll yang tidak pasti yang didefinisikan oleh CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Kecocokan yang dapat dibaca manusia dengan aturan khusus (Semua budaya lain):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
maks
sumber
18

Seperti kata Ed , CompareTo digunakan untuk menyortir.

Namun, ada perbedaan antara .Equals dan ==.

== memutuskan untuk pada dasarnya kode berikut:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

Alasan sederhananya adalah hal berikut ini akan menimbulkan pengecualian:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

Dan yang berikut tidak akan:

string a = null;
string b = "foo";

bool equal = a == b;
Jonathan C Dickinson
sumber
15

Penjelasan dan praktik yang baik tentang masalah perbandingan string dapat ditemukan di artikel Rekomendasi Baru untuk Menggunakan Strings di Microsoft .NET 2.0 dan juga di Praktik Terbaik untuk Menggunakan Strings di .NET Framework .


Setiap metode yang disebutkan (dan lainnya) memiliki tujuan tertentu. Perbedaan utama di antara mereka adalah jenis StringComparison Enumeration yang mereka gunakan secara default. Ada beberapa opsi:

  • Budaya Saat Ini
  • CurrentCultureIgnoreCase
  • Budaya Invariant
  • InvariantCultureIgnoreCase
  • Urut
  • OrdinalIgnoreCase

Setiap jenis perbandingan di atas menargetkan penggunaan yang berbeda:

  • Urut
    • Pengidentifikasi internal peka huruf besar-kecil
    • Pengidentifikasi case-sensitive dalam standar seperti XML dan HTTP
    • Pengaturan terkait keamanan kasus-sensitif
  • OrdinalIgnoreCase
    • Pengidentifikasi internal case-insensitive
    • Pengidentifikasi case-insensitive dalam standar seperti XML dan HTTP
    • Jalur file (di Microsoft Windows)
    • Nilai / kunci registri
    • Variabel lingkungan
    • Pengidentifikasi sumber daya (menangani nama, misalnya)
    • Pengaturan terkait keamanan case sensitif
  • InvariantCulture atau InvariantCultureIgnoreCase
    • Beberapa data yang relevan secara linguistik tetap ada
    • Tampilan data linguistik yang membutuhkan urutan pengurutan yang tetap
  • CurrentCulture atau CurrentCultureIgnoreCase
    • Data ditampilkan kepada pengguna
    • Sebagian besar input pengguna

Catatan, bahwa StringComparison Enumeration serta kelebihan untuk metode perbandingan string, ada sejak .NET 2.0.


Metode String.CompareTo (String)

Sebenarnya jenis implementasi aman Metode IComparable.CompareTo . Interpretasi default: CurrentCulture.

Pemakaian:

Metode CompareTo dirancang terutama untuk digunakan dalam operasi penyortiran atau abjad

Jadi

Menerapkan antarmuka IComparable tentu akan menggunakan metode ini

Metode Membandingkan

Anggota statis dari Kelas String yang memiliki banyak kelebihan. Interpretasi default: CurrentCulture.

Kapan pun memungkinkan, Anda harus memanggil kelebihan metode Compare yang menyertakan parameter StringComparison.

Metode String.Equals

Override dari kelas Object dan overload untuk keamanan tipe. Interpretasi standar: Ordinal. Perhatikan itu:

Metode persamaan kelas String termasuk Persamaan statis , operator statis == , dan metode contoh Persamaan .


Kelas StringComparer

Ada juga cara lain untuk menangani perbandingan string terutama bertujuan untuk menyortir:

Anda bisa menggunakan kelas StringComparer untuk membuat perbandingan tipe khusus untuk mengurutkan elemen dalam koleksi generik. Kelas-kelas seperti Hashtable, Kamus, SortedList, dan SortedList menggunakan kelas StringComparer untuk keperluan penyortiran.

Ryszard Dżegan
sumber
2
Menurut beberapa posting lain di SO, semua metode selain yang ordinal memiliki kasus di mana Compare (a, b) dan Compare (b, a) dapat keduanya mengembalikan 1, dan bug telah diklasifikasikan sebagai "tidak akan diperbaiki ". Karena itu, saya tidak yakin setiap perbandingan tersebut memiliki setiap kasus penggunaan.
supercat
@supercat dapatkah Anda menautkannya, atau memberikan contoh?
Noctis
1
Lihat stackoverflow.com/questions/17599084/… untuk pembahasan masalah ini.
supercat
7

Bukan berarti kinerja biasanya penting dengan 99% dari waktu Anda perlu melakukan ini, tetapi jika Anda harus melakukan ini dalam satu lingkaran beberapa juta kali saya akan sangat menyarankan Anda menggunakan .Equals atau == karena segera setelah itu menemukan karakter yang tidak cocok itu membuang semuanya sebagai salah, tetapi jika Anda menggunakan CompareTo itu harus mencari tahu karakter mana yang kurang dari yang lain, yang mengarah ke waktu kinerja yang sedikit lebih buruk.

Jika aplikasi Anda akan berjalan di berbagai negara, saya sarankan Anda melihat implikasi CultureInfo dan mungkin menggunakan .Equals. Karena saya hanya benar-benar menulis aplikasi untuk AS (dan tidak peduli jika itu tidak berfungsi dengan baik oleh seseorang), saya selalu menggunakan ==.

kejelasan
sumber
5

Dalam formulir yang Anda daftarkan di sini, tidak ada banyak perbedaan di antara keduanya. CompareToakhirnya memanggil CompareInfometode yang melakukan perbandingan menggunakan budaya saat ini; Equalsdipanggil oleh ==operator.

Jika Anda mempertimbangkan kelebihan, maka segalanya menjadi berbeda. Comparedan ==hanya bisa menggunakan budaya saat ini untuk membandingkan string. Equalsdan String.Comparedapat mengambil StringComparisonargumen enumerasi yang memungkinkan Anda menentukan perbandingan budaya-tidak sensitif atau tidak sensitif-kasus. Hanya String.Comparememungkinkan Anda untuk menentukan CultureInfodan melakukan perbandingan menggunakan budaya selain budaya default.

Karena sifatnya yang fleksibel, saya menemukan saya menggunakan String.Comparelebih dari metode perbandingan lainnya; itu memungkinkan saya menentukan dengan tepat apa yang saya inginkan.

OwenP
sumber
2

Satu perbedaan besar yang perlu diperhatikan adalah .Equals () akan mengeluarkan pengecualian jika string pertama adalah null, sedangkan == tidak akan.

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
Rauld
sumber
0
  • s1.CompareTo (s2): JANGAN gunakan jika tujuan utama adalah untuk menentukan apakah dua string setara
  • s1 == s2: Tidak bisa mengabaikan kasus
  • s1.Equals (s2, StringComparison): Melempar NullReferenceException jika s1 adalah nol
  • String.Equals (s2, StringComparison): Dengan proses eliminasi, metode statis ini adalah PEMENANG (mengasumsikan use case yang umum untuk menentukan apakah dua string setara)!
John DiFini
sumber
-1

Menggunakan .Equals juga jauh lebih mudah dibaca .

hometoast
sumber
-9

dengan .Equals, Anda juga mendapatkan opsi StringComparison. sangat berguna untuk mengabaikan case dan hal lainnya.

btw, ini akan dinilai salah

string a = "myString";
string b = "myString";

return a==b

Karena == membandingkan nilai a dan b (yang merupakan pointer) ini hanya akan bernilai true jika pointer menunjuk ke objek yang sama dalam memori. .Menyamakan dereferensi pointer dan membandingkan nilai yang disimpan di pointer. a. Setara (b) akan benar di sini.

dan jika Anda mengubah b ke:

b = "MYSTRING";

maka a.Equals (b) salah, tetapi

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

akan benar

a.CompareTo (b) memanggil fungsi CompareTo string yang membandingkan nilai-nilai pada pointer dan mengembalikan <0 jika nilai yang disimpan di a lebih kecil dari nilai yang disimpan di b, mengembalikan 0 jika a. Sama dengan (b) benar, dan > 0 sebaliknya. Namun, ini peka huruf besar-kecil, saya pikir ada beberapa opsi bagi CompareTo untuk mengabaikan huruf besar dan kecil, tetapi tidak punya waktu untuk melihat sekarang. Seperti yang telah dinyatakan orang lain, ini akan dilakukan untuk menyortir. Membandingkan kesetaraan dengan cara ini akan menghasilkan overhead yang tidak perlu.

Saya yakin saya meninggalkan barang, tetapi saya pikir ini harus menjadi info yang cukup untuk mulai bereksperimen jika Anda memerlukan detail lebih lanjut.

David
sumber
9
Bagian a == b salah. Operator == secara efektif kelebihan beban untuk kelas String dan membandingkan nilai-nilai terlepas dari referensi yang sebenarnya.
Goyuix