Dize farklılıkları C # yöntemleri karşılaştırmak


261

C # 'da dize karşılaştırmak oldukça basittir. Aslında bunu yapmanın birkaç yolu vardır. Bazılarını aşağıdaki blokta listeledim. Merak ettiğim şey, aralarındaki farklar ve biri diğeri üzerinde ne zaman kullanılmalı? Ne pahasına olursa olsun bunlardan kaçınılmalı mı? Listelemediğim başka şeyler var mı?

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

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

(Not: Bu örnekte eşitlik arıyorum, daha az veya daha fazla değil, bununla ilgili yorum yapmaktan çekinmeyin)


4
Bir tuzak, stringValue.Equals (null) yapamamanızdır, çünkü null'da bir yöntemi çağırabileceğinizi varsayar
johnc 0


@RobertHarvey Stackoverflow için gelmek nedeni, böylece cevaplar için birden fazla sayfa okumak zorunda kalmamdır.
Syaiful Nizam Yahya

@Syaiful: Ben yığın taşması gelmek nedeni cevapları bulmaktır değil belgelerinde.
Robert Harvey

Yanıtlar:


231

Bu işlevlerin nasıl çalıştığına ilişkin kurallar şunlardır:

stringValue.CompareTo(otherStringValue)

  1. null bir dizeden önce gelir
  2. kullanır CultureInfo.CurrentCulture.CompareInfo.Compare, yani kültüre bağlı bir karşılaştırma kullanır. Bu , Almanya veya benzeri ile ßkarşılaştırılacağı anlamına gelebilirSS

stringValue.Equals(otherStringValue)

  1. null hiçbir şeye eşit kabul edilmez
  2. bir StringComparisonseçenek belirtmedikçe , doğrudan sıralı eşitlik denetimi gibi görünen bir öğeyi kullanır, yani herhangi bir dilde veya kültürde ßaynı değildirSS

stringValue == otherStringValue

  1. İle aynı değil stringValue.Equals().
  2. ==Operatör statik çağıran Equals(string a, string b)sırayla bir iç gider yöntemini ( EqualsHelperkarşılaştırma yapmak.
  3. .Equals()Bir nulldizede çağrı yapmak nullreferans istisnası alırken açık ==değildir.

Object.ReferenceEquals(stringValue, otherStringValue)

Sadece referansların aynı olup olmadığını kontrol eder, yani sadece aynı içeriğe sahip iki dize değildir, bir dize nesnesini kendisiyle karşılaştırırsınız.


Yukarıdaki yöntem çağrılarını kullanan seçeneklerle, nasıl karşılaştırılacağını belirtmek için daha fazla seçeneğe sahip aşırı yükler olduğunu unutmayın.

Eşitliği kontrol etmek istiyorsanız tavsiyem, kültüre bağlı bir karşılaştırma kullanmak isteyip istemediğinizi kararlaştırmak ve sonra seçime bağlı olarak .CompareToveya seçeneğini kullanmaktır .Equals.


5
"stringValue.Equals (otherStringValue): null null değerine eşit değil" Lol, söylemem. null, ObjectReferenceNotSet istisnasına eşittir.
Kevin

29
== .Equals () ile aynı değildir ... == operatörü, statik Eşittir (dize a, dize b) yöntemini çağırır (bu da karşılaştırmayı yapmak için dahili bir EqualsHelper'a gider. string = null referans hariç, == değil.
Dan C.

2
Öte yandan, .Equals biraz daha hızlıdır (dahili olarak daha az bir yöntem çağrısı), ancak daha az okunabilir - elbette :).
Dan C.

Ben '==' referans karşılaştırmaları ve object.equals değer karşılaştırmaları yapacak düşünüyordum.How '==' ve string.equals aynı şekilde çalışır?
amesh

@ LasseV.Karlsen Ne düşünüyorsun String.Compare?
JDandChips

72

MSDN'den:

"CompareTo yöntemi öncelikle sıralama veya alfabetik işlemlerde kullanılmak üzere tasarlanmıştır. Yöntem çağrısının birincil amacı iki dizenin eşdeğer olup olmadığını belirlemek olduğunda kullanılmamalıdır. İki dizenin eşdeğer olup olmadığını belirlemek için Eşittir yöntemini çağırın. "

Yalnızca eşitlik ararken .Equalsyerine kullanmayı önerirler .CompareTo. Ben arasında bir fark olup olmadığından emin değilim .Equalsve ==için stringsınıfta. Bazen birisinin daha sonra gelmesi ve bu sınıf için operatörü yeniden tanımlaması durumunda kendi sınıflarım için .Equalsveya Object.ReferenceEqualsbunun yerine kullanacağım .====


18
Bu sana hiç oldu mu? (Yeniden tanımlanıyor ==) ... Waaaay çok defansif programlama olarak görüyorum =)
juan

Evet, bu yüzden şimdi nesne eşitliği ararken Object.ReferenceEquals kullanıyorum :). Biraz aşırı savunma olabilir, ama bu konuda manyak değilim ve doğrusu bu durum çok sık ortaya çıkmıyor.
Ed S.

Bu 'savunma kodlamasının' faydalı olduğundan şüpheliyim. Sınıf sahibinin == işlecini geçersiz kılması gerekiyorsa, hiç kimsenin onu kullanmadığını öğrenirse ne olur?
Dave Van den Eynde

1
@DaveVandenEynde: Evet ... Bunu bir süre önce yazdım. Bunu düzenli olarak yapmıyorum, sadece geçersiz kılıyorum.
Ed

1
Microsoft'un önerisi burada kaydedilmiştir: .NET Framework'te Dizeleri Kullanmak için En İyi Uygulamalar
JJS

50

BCL yöntemlerindeki farklılıkları merak ediyorsanız, Reflector arkadaşınızdır :-)

Bu yönergeleri takip ediyorum:

Tam eşleme: DÜZENLEME: Daha önce her zaman == operatörünün Eşittir (dize, dize) içinde nesne == operatörünün nesne referanslarını karşılaştırmak için kullanıldığı, ancak strA.Equals (strB) hala% 1-11 olduğu prensibi ile kullandım dize (strA, strB), strA == strB ve string.CompareOrdinal (strA, strB). Aynı / farklı dize uzunlukları ve değişen boyutlarda (1B - 5MB) hem interned / interned dize değerlerinde bir StopWatch ile test ettik.

strA.Equals(strB)

İnsan tarafından okunabilir eşleşme (Batı kültürleri, büyük / küçük harfe duyarsız):

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

İnsan tarafından okunabilir eşleşme (CultureInfo tarafından tanımlanan diğer tüm kültürler, duyarsız vaka / aksan / kana / vb.):

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

Özel kurallarla insan tarafından okunabilir eşleşme (Diğer tüm kültürler):

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

18

As Ed dedi CompareTo sıralamak için kullanılır.

Ancak, .Equals ve == arasında bir fark vardır.

== aslında aşağıdaki kodu çözer :

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

Bunun basit nedeni, aşağıdakilerin bir istisna oluşturacağıdır:

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

bool equal = a.Equals(b);

Ve aşağıdakiler olmayacak:

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

bool equal = a == b;

15

Dize karşılaştırma sorunlarıyla ilgili iyi açıklama ve uygulamalar Microsoft .NET 2.0'da Dizeleri Kullanmaya Yönelik Yeni Öneriler makalesinde ve ayrıca .NET Framework'te Dizeleri Kullanma En İyi Yöntemleri makalesinde bulunabilir .


Bahsedilen yöntemin (ve diğer) her birinin belirli bir amacı vardır. Aralarındaki en önemli fark , varsayılan olarak ne tür StringComparison Numaralandırma kullandıklarıdır. Birkaç seçenek vardır:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • sıra
  • OrdinalIgnoreCase

Yukarıdaki karşılaştırma türünün her biri farklı kullanım durumunu hedefler:

  • sıra
    • Büyük / küçük harfe duyarlı dahili tanımlayıcılar
    • XML ve HTTP gibi standartlarda büyük / küçük harfe duyarlı tanımlayıcılar
    • Büyük / küçük harfe duyarlı güvenlikle ilgili ayarlar
  • OrdinalIgnoreCase
    • Büyük / küçük harfe duyarlı olmayan dahili tanımlayıcılar
    • XML ve HTTP gibi standartlarda büyük / küçük harfe duyarlı olmayan tanımlayıcılar
    • Dosya yolları (Microsoft Windows'ta)
    • Kayıt defteri anahtarları / değerleri
    • Ortam Değişkenleri
    • Kaynak tanımlayıcıları (örneğin tanıtıcı adları)
    • Büyük / küçük harfe duyarlı olmayan güvenlikle ilgili ayarlar
  • InvariantCulture veya InvariantCultureIgnoreCase
    • Bazı dillerle ilgili veriler devam etti
    • Sabit sıralama düzeni gerektiren dil verilerinin görüntülenmesi
  • CurrentCulture veya CurrentCultureIgnoreCase
    • Kullanıcıya görüntülenen veriler
    • Çoğu kullanıcı girişi

Not ki StringComparison Sayım yanı sıra dize karşılaştırma yöntemleri için aşırı yükler, .NET 2.0 beri var.


String.CompareTo Method (String)

Aslında IComparable.CompareTo Yöntemi türü güvenli uygulamasıdır . Varsayılan yorumlama: CurrentCulture.

Kullanımı:

CompareTo yöntemi öncelikle sıralama veya alfabetik işlemlerde kullanılmak üzere tasarlanmıştır

Böylece

IComparable arabiriminin uygulanması mutlaka bu yöntemi kullanacaktır

String.Compare Yöntemi

Aşırı yüke sahip String Sınıfının statik bir üyesi . Varsayılan yorumlama: CurrentCulture.

Mümkün olduğunda, bir StringComparison parametresi içeren Compare yönteminin aşırı yüklenmesini çağırmalısınız.

String.Equals Yöntemi

Nesne sınıfından geçersiz kılın ve tür güvenliği için aşırı yüklendi. Varsayılan yorum: Sıradan. Dikkat:

String sınıfının eşitlik yöntemleri statik Eşittir , statik işleç == ve Eşittir örnek yöntemini içerir .


StringComparer sınıfı

Dizgi karşılaştırmalarıyla başa çıkmanın başka bir yolu da özellikle sıralamayı amaçlamaktadır:

Genel bir koleksiyondaki öğeleri sıralamak için türe özgü bir karşılaştırma oluşturmak üzere StringComparer sınıfını kullanabilirsiniz . Hashtable, Dictionary, SortedList ve SortedList gibi sınıflar, sıralama amacıyla StringComparer sınıfını kullanır.


2
SO'daki diğer bazı yayınlara göre, sıralı olanlar dışındaki tüm yöntemlerin Karşılaştır (a, b) ve Karşılaştır (b, a) öğelerinin her ikisinin de 1 döndürebileceği ve hatanın "düzeltilmeyeceği" olarak sınıflandırıldığı durumlar vardır. ". Bu nedenle, bu tür karşılaştırmaların herhangi bir kullanım durumu olduğundan emin değilim .
supercat

@supercat buna bağlantı verebilir veya bir örnek verebilir misiniz?
Noctis

1
Sorunun tartışması için stackoverflow.com/questions/17599084/… adresine bakın .
supercat

7

Bu performans genellikle bunu yapmanız gereken zamanların% 99'uyla önemli değildir, ancak bunu birkaç milyon kez bir döngüde yapmak zorunda kalırsanız .Equals veya == kullanmanız önerilir, çünkü bir karakter bulur bulmaz eşleşmeyen her şeyi yanlış olarak atar, ancak CompareTo kullanırsanız, hangi karakterin diğerinden daha az olduğunu bulması gerekir, bu da biraz daha kötü performans süresine yol açar.

Uygulamanız farklı ülkelerde yayınlanacaksa, CultureInfo uygulamalarına bir göz atmanızı ve muhtemelen .Equals kullanmanızı öneririm. Yalnızca ABD için gerçekten uygulamalar yazdım (ve birileri tarafından düzgün çalışmıyorsa umurumda değil), her zaman sadece == kullanıyorum.


5

Burada listelediğiniz formlarda, ikisi arasında çok fazla fark yoktur. mevcut kültürü kullanarak bir karşılaştırma CompareToyapan bir CompareInfometodu çağırır ; operatör Equalstarafından çağrılır ==.

Aşırı yükleri düşünürseniz, işler farklılaşır. Compareve ==bir dize karşılaştırmak için yalnızca geçerli kültürü kullanabilir. Equalsve kültüre duyarsız veya büyük / küçük harfe duyarlı olmayan karşılaştırmalar belirtmenize olanak tanıyan String.Comparebir StringComparisonnumaralandırma argümanı alabilir . Yalnızca String.Comparea'yı belirtmenize CultureInfove varsayılan kültür dışında bir kültür kullanarak karşılaştırmalar gerçekleştirmenize izin verir .

Çok yönlülüğü nedeniyle, String.Comparediğer karşılaştırma yöntemlerinden daha fazlasını kullandığımı fark ettim ; tam olarak ne istediğimi belirtmeme izin veriyor.


2

Dikkat edilmesi gereken bir büyük fark, ilk dize null ise .Equals () bir istisna atar, oysa == olmaz.

       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");

0
  • s1.CompareTo (s2): Birincil amaç iki dizenin eşdeğer olup olmadığını belirlemekse KULLANMAYIN
  • s1 == s2: Büyük / küçük harf göz ardı edilemez
  • s1.Equals (s2, StringComparison): s1 boşsa NullReferenceException özel durumunu atar
  • String.Equals (s2, StringComparison): eliminiation süreci olarak, bu statik bir yöntemdir KAZANAN (iki dize eşdeğerdir olmadığını belirlemek için tipik bir kullanım örneği varsayarak)!


-9

.Equals ile StringComparison seçeneklerini de kazanırsınız. davayı ve diğer şeyleri görmezden gelmek için çok kullanışlı.

btw, bu yanlış olarak değerlendirilir

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

return a==b

== a ve b (işaretçiler) değerlerini karşılaştırdığından, bu yalnızca işaretçiler bellekteki aynı nesneyi gösteriyorsa doğru olarak değerlendirilir. Eşittir işaretçileri dereferences ve işaretçiler depolanan değerleri karşılaştırır. a. (b) bendi burada doğrudur.

ve b'yi şu şekilde değiştirirseniz:

b = "MYSTRING";

a. (b) paragrafları yanlıştır, ancak

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

doğru olur

a.CompareTo (b), dizgideki değerleri karşılaştıran ve a'da saklanan değer b'de saklanan değerden küçükse <0 döndüren dizenin CompareTo işlevini çağırır, a. > 0 aksi takdirde. Ancak, bu büyük / küçük harfe duyarlıdır, ben CompareTo büyük / küçük harfleri göz ardı etmek için seçenekler olduğunu düşünüyorum, ama şimdi bakmak için zaman yok. Diğerlerinin de belirttiği gibi, bu sıralama için yapılır. Eşitliğin bu şekilde karşılaştırılması gereksiz ek yüke neden olacaktır.

Eminim bir şeyleri dışarıda bırakıyorum, ancak daha fazla ayrıntıya ihtiyacınız varsa denemeye başlamak için yeterli bilgi olması gerektiğini düşünüyorum.


9
A == b bölümü yanlış. == işleci String sınıfı için etkin bir şekilde aşırı yüklenmiştir ve gerçek referanslara bakılmaksızın değerleri karşılaştırır.
Goyuix
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.