Unterschiede in den Methoden zum Vergleichen von Zeichenfolgen in C #

261

Der Vergleich von Zeichenfolgen in C # ist ziemlich einfach. In der Tat gibt es mehrere Möglichkeiten, dies zu tun. Ich habe einige im Block unten aufgelistet. Worauf ich neugierig bin, sind die Unterschiede zwischen ihnen und wann einer über den anderen verwendet werden sollte? Sollte man um jeden Preis vermieden werden? Gibt es noch mehr, die ich nicht aufgelistet habe?

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

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

(Hinweis: Ich suche in diesem Beispiel nach Gleichheit, nicht kleiner oder größer als, aber ich kann dies auch gerne kommentieren.)

Craig
quelle
4
Eine Falle ist, dass Sie stringValue.Equals (null) nicht ausführen können, da dies voraussetzt, dass Sie eine Methode für null
aufrufen können
1
MSDN Referenz
Robert Harvey
@RobertHarvey Der Grund, warum ich zu Stackoverflow komme, ist, dass ich nicht mehrere Seiten lesen muss, um Antworten zu erhalten.
Syaiful Nizam Yahya
@Syaiful: Der Grund, warum ich zu Stack Overflow komme, ist, Antworten zu finden, die nicht in der Dokumentation enthalten sind.
Robert Harvey

Antworten:

230

Hier sind die Regeln für die Funktionsweise dieser Funktionen:

stringValue.CompareTo(otherStringValue)

  1. null kommt vor einer Schnur
  2. es verwendet CultureInfo.CurrentCulture.CompareInfo.Compare, was bedeutet, dass es einen kulturabhängigen Vergleich verwendet. Dies könnte bedeuten, dass ßvergleichbar mit SSin Deutschland oder ähnlich

stringValue.Equals(otherStringValue)

  1. null wird als gleichwertig angesehen
  2. Wenn Sie keine StringComparisonOption angeben , wird eine direkte ordinale Gleichheitsprüfung verwendet , die in keiner Sprache oder Kultur ßidentisch SSist

stringValue == otherStringValue

  1. Ist nicht dasselbe wie stringValue.Equals().
  2. Der ==Operator ruft die statische Equals(string a, string b)Methode auf (die wiederum an eine interne Methode geht EqualsHelper, um den Vergleich durchzuführen.
  3. Das Aufrufen .Equals()einer nullZeichenfolge führt zu einer nullReferenzausnahme, während dies bei on ==nicht der Fall ist.

Object.ReferenceEquals(stringValue, otherStringValue)

Überprüft nur, ob Referenzen gleich sind, dh es sind nicht nur zwei Zeichenfolgen mit demselben Inhalt, sondern Sie vergleichen ein Zeichenfolgenobjekt mit sich selbst.


Beachten Sie, dass es bei den oben genannten Optionen, die Methodenaufrufe verwenden, Überladungen mit mehr Optionen gibt, mit denen angegeben werden kann, wie verglichen werden soll.

Mein Rat, wenn Sie nur auf Gleichheit prüfen möchten, ist, sich zu entscheiden, ob Sie einen kulturabhängigen Vergleich verwenden möchten oder nicht, und dann .CompareTooder .Equals, je nach Wahl, zu verwenden.

Lasse V. Karlsen
quelle
5
"stringValue.Equals (otherStringValue): null ist nicht gleich null" Lol, ich würde nicht sagen. null entspricht der ObjectReferenceNotSet-Ausnahme.
Kevin
29
== ist nicht dasselbe wie .Equals () ... Der Operator == ruft die statische Methode Equals (Zeichenfolge a, Zeichenfolge b) auf (die wiederum an einen internen EqualsHelper geht, um den Vergleich durchzuführen. Aufrufen von .Equals auf einer Null Zeichenfolge erhält null Referenz exkl., während on == nicht.
Dan C.
2
Auf der anderen Seite ist .Equals etwas schneller (ein Methodenaufruf weniger intern), aber weniger lesbar - wohl natürlich :).
Dan C.
Ich dachte, '==' führt Referenzvergleiche durch und object.equals führt Wertevergleiche durch. Wie funktionieren '==' und string.equals gleich?
Amesh
@ LasseV.Karlsen Wie ist deine Meinung dazu String.Compare?
JDandChips
72

Von MSDN:

"Die CompareTo-Methode wurde hauptsächlich für Sortier- oder Alphabetisierungsvorgänge entwickelt. Sie sollte nicht verwendet werden, wenn der Hauptzweck des Methodenaufrufs darin besteht, festzustellen, ob zwei Zeichenfolgen gleichwertig sind. Um festzustellen, ob zwei Zeichenfolgen gleichwertig sind, rufen Sie die Equals-Methode auf. ""

Sie schlagen vor, .Equalsstatt .CompareTonur nach Gleichheit zu suchen. Ich bin mir nicht sicher, ob es einen Unterschied zwischen .Equalsund ==für die stringKlasse gibt. Ich werde manchmal .Equalsoder Object.ReferenceEqualsanstelle von ==für meine eigenen Klassen verwenden, falls jemand zu einem späteren Zeitpunkt vorbeikommt und den ==Operator für diese Klasse neu definiert .

Ed S.
quelle
18
Ist dir das jemals passiert? (Redefining ==) ... Ich sehe es als waaaay zu defensiver Programmierung =)
juan
Ja, deshalb verwende ich jetzt Object.ReferenceEquals, wenn ich nach Objektgleichheit suche :). Es mag ein bisschen zu defensiv sein, aber ich bin nicht verrückt danach und ehrlich gesagt taucht diese Situation nicht sehr oft auf.
Ed S.
Ich bezweifle, dass diese "defensive Codierung" nützlich ist. Was ist, wenn der Klassenbesitzer den Operator == überschreiben muss und dann herausfindet, dass niemand ihn verwendet?
Dave Van den Eynde
1
@ DaveVandenEynde: Ja ... ich habe das vor einiger Zeit geschrieben. Ich mache das nicht regelmäßig, sondern überschreibe es nur. Gleich, wenn es angebracht ist.
Ed S.
1
Die Empfehlung von Microsoft wird hier aufgezeichnet: Best Practices für die Verwendung von Zeichenfolgen in .NET Framework
JJS
50

Wenn Sie jemals neugierig auf Unterschiede in den BCL-Methoden sind, ist Reflector Ihr Freund :-)

Ich folge diesen Richtlinien:

Genaue Übereinstimmung: BEARBEITEN: Ich habe zuvor immer den Operator == verwendet, nach dem Prinzip, dass innerhalb von Equals (Zeichenfolge, Zeichenfolge) der Operator object == verwendet wird, um die Objektreferenzen zu vergleichen, aber es scheint, dass strA.Equals (strB) immer noch 1-11% beträgt Insgesamt schneller als string.Equals (strA, strB), strA == strB und string.CompareOrdinal (strA, strB). Ich habe eine Schleife mit einer StopWatch sowohl für internierte als auch für nicht internierte Zeichenfolgenwerte mit gleichen / unterschiedlichen Zeichenfolgenlängen und unterschiedlichen Größen (1B bis 5 MB) getestet.

strA.Equals(strB)

Vom Menschen lesbare Übereinstimmung (westliche Kulturen, ohne Berücksichtigung der Groß- und Kleinschreibung):

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

Vom Menschen lesbare Übereinstimmung (Alle anderen Kulturen, unempfindlicher Fall / Akzent / Kana / usw., definiert von CultureInfo):

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

Vom Menschen lesbare Übereinstimmung mit benutzerdefinierten Regeln (alle anderen Kulturen):

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

Wie Ed sagte, wird CompareTo zum Sortieren verwendet.

Es gibt jedoch einen Unterschied zwischen .Equals und ==.

== löst im Wesentlichen den folgenden Code auf:

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

Der einfache Grund ist, dass Folgendes eine Ausnahme auslöst:

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

bool equal = a.Equals(b);

Und das wird nicht:

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

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

Gute Erklärungen und Vorgehensweisen zu Problemen beim Vergleichen von Zeichenfolgen finden Sie im Artikel Neue Empfehlungen für die Verwendung von Zeichenfolgen in Microsoft .NET 2.0 sowie in den Best Practices für die Verwendung von Zeichenfolgen in .NET Framework .


Jede der genannten Methoden (und andere) hat einen bestimmten Zweck. Der Hauptunterschied zwischen ihnen besteht darin, welche Art von StringComparison-Aufzählung sie standardmäßig verwenden. Es gibt mehrere Möglichkeiten:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • Ordinal
  • OrdinalIgnoreCase

Jeder der oben genannten Vergleichstypen zielt auf unterschiedliche Anwendungsfälle ab:

  • Ordinal
    • Interne Bezeichner, bei denen zwischen Groß- und Kleinschreibung unterschieden wird
    • Groß- und Kleinschreibung in Standards wie XML und HTTP
    • Sicherheitsbezogene Einstellungen, bei denen zwischen Groß- und Kleinschreibung unterschieden wird
  • OrdinalIgnoreCase
    • Interne Bezeichner, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird
    • Groß- und Kleinschreibung wird in Standards wie XML und HTTP nicht berücksichtigt
    • Dateipfade (unter Microsoft Windows)
    • Registrierungsschlüssel / -werte
    • Umgebungsvariablen
    • Ressourcenkennungen (z. B. Handle-Namen)
    • Sicherheitsbezogene Einstellungen ohne Berücksichtigung der Groß- und Kleinschreibung
  • InvariantCulture oder InvariantCultureIgnoreCase
    • Einige behielten sprachlich relevante Daten bei
    • Anzeige von Sprachdaten, die eine feste Sortierreihenfolge erfordern
  • CurrentCulture oder CurrentCultureIgnoreCase
    • Dem Benutzer angezeigte Daten
    • Die meisten Benutzereingaben

Beachten Sie, dass die StringComparison-Aufzählung sowie Überladungen für Zeichenfolgenvergleichsmethoden seit .NET 2.0 vorhanden sind.


String.CompareTo-Methode (String)

Ist in der Tat typsichere Implementierung der IComparable.CompareTo-Methode . Standardinterpretation: CurrentCulture.

Verwendungszweck:

Die CompareTo-Methode wurde hauptsächlich für Sortier- oder Alphabetisierungsvorgänge entwickelt

So

Bei der Implementierung der IComparable-Schnittstelle wird diese Methode unbedingt verwendet

String.Compare-Methode

Ein statisches Mitglied der String-Klasse mit vielen Überladungen. Standardinterpretation: CurrentCulture.

Wann immer möglich, sollten Sie eine Überladung der Compare-Methode aufrufen, die einen StringComparison-Parameter enthält.

String.Equals-Methode

Überschreiben von Objektklasse und aus Gründen der Typensicherheit überladen. Standardinterpretation: Ordnungszahl. Beachte das:

Die Gleichheitsmethoden der String-Klasse umfassen die statischen Gleichungen , den statischen Operator == und die Instanzmethode Gleich .


StringComparer-Klasse

Es gibt auch eine andere Möglichkeit, mit Zeichenfolgenvergleichen umzugehen, die insbesondere auf das Sortieren abzielt:

Mit der StringComparer-Klasse können Sie einen typspezifischen Vergleich erstellen, um die Elemente in einer generischen Auflistung zu sortieren. Klassen wie Hashtable, Dictionary, SortedList und SortedList verwenden die StringComparer-Klasse zum Sortieren.

Ryszard Dżegan
quelle
2
Gemäß einigen anderen Beiträgen zu SO gibt es bei allen Methoden außer den ordinalen Fällen Fälle, in denen Compare (a, b) und Compare (b, a) beide 1 zurückgeben können und der Fehler als "wird nicht behoben" eingestuft wurde ". Als solche bin sicher , dass ich keine solche Vergleiche haben jeden Anwendungsfall.
Supercat
@supercat kannst du darauf verlinken oder ein Beispiel geben?
Noctis
1
Eine Diskussion des Problems finden Sie unter stackoverflow.com/questions/17599084/… .
Supercat
7

Nicht, dass die Leistung in 99% der Fälle von Bedeutung ist, aber wenn Sie dies mehrere Millionen Mal in einer Schleife tun müssten, würde ich Ihnen dringend empfehlen, .Equals oder == zu verwenden, da sobald ein Charakter gefunden wird das stimmt nicht überein, wirft das Ganze als falsch heraus, aber wenn Sie CompareTo verwenden, muss es herausfinden, welcher Charakter kleiner als der andere ist, was zu einer etwas schlechteren Aufführungszeit führt.

Wenn Ihre App in verschiedenen Ländern ausgeführt wird, empfehlen wir Ihnen, sich die Auswirkungen von CultureInfo anzusehen und möglicherweise .Equals zu verwenden. Da ich nur Apps für die USA schreibe (und es mir egal ist, ob es von jemandem nicht richtig funktioniert), verwende ich immer nur ==.

Viggity
quelle
5

In den hier aufgeführten Formularen gibt es keinen großen Unterschied zwischen den beiden. CompareToAm Ende wird eine CompareInfoMethode aufgerufen, die einen Vergleich unter Verwendung der aktuellen Kultur durchführt. Equalswird vom ==Operator aufgerufen .

Wenn Sie Überlastungen berücksichtigen, werden die Dinge anders. Compareund ==kann nur die aktuelle Kultur verwenden, um eine Zeichenfolge zu vergleichen. Equalsund String.Comparekann ein StringComparisonAufzählungsargument verwenden, mit dem Sie kulturunabhängige oder fallunabhängige Vergleiche angeben können. Sie können nur String.Compareeine angeben CultureInfound Vergleiche mit einer anderen Kultur als der Standardkultur durchführen.

Aufgrund seiner Vielseitigkeit verwende ich String.Comparemehr als jede andere Vergleichsmethode. Damit kann ich genau angeben, was ich will.

OwenP
quelle
2

Ein großer Unterschied ist .Equals () löst eine Ausnahme aus, wenn die erste Zeichenfolge null ist, während == dies nicht tut.

       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
quelle
0
  • s1.CompareTo (s2): NICHT verwenden, wenn der Hauptzweck darin besteht, festzustellen, ob zwei Zeichenfolgen gleichwertig sind
  • s1 == s2: Groß- / Kleinschreibung kann nicht ignoriert werden
  • s1.Equals (s2, StringComparison): Löst eine NullReferenceException aus, wenn s1 null ist
  • String.Equals (s2, StringComparison): Nach dem Eliminierungsprozess ist diese statische Methode der GEWINNER (unter der Annahme eines typischen Anwendungsfalls, um festzustellen, ob zwei Zeichenfolgen gleichwertig sind)!
John DiFini
quelle
-1

Die Verwendung von .Equals ist auch viel einfacher zu lesen .

Hometoast
quelle
-9

Mit .Equals erhalten Sie auch die StringComparison-Optionen. Sehr praktisch, um Koffer und andere Dinge zu ignorieren.

Übrigens wird dies als falsch ausgewertet

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

return a==b

Da == die Werte von a und b (die Zeiger sind) vergleicht, wird dies nur dann als wahr ausgewertet, wenn die Zeiger auf dasselbe Objekt im Speicher zeigen. Gleichungen dereferenzieren die Zeiger und vergleichen die an den Zeigern gespeicherten Werte. a.Gleichungen (b) wären hier wahr.

und wenn Sie b ändern zu:

b = "MYSTRING";

dann ist a.Equals (b) falsch, aber

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

wäre wahr

a.CompareTo (b) ruft die CompareTo-Funktion des Strings auf, die die Werte an den Zeigern vergleicht und <0 zurückgibt, wenn der bei a gespeicherte Wert kleiner als der bei b gespeicherte Wert ist, und 0 zurückgibt, wenn a.Equals (b) true ist, und > 0 sonst. Dies unterscheidet jedoch zwischen Groß- und Kleinschreibung. Ich denke, es gibt möglicherweise Optionen für CompareTo, um Groß- und Kleinschreibung und dergleichen zu ignorieren, aber Sie haben jetzt keine Zeit, nachzuschauen. Wie andere bereits angegeben haben, würde dies zum Sortieren erfolgen. Ein Vergleich der Gleichheit auf diese Weise würde zu unnötigem Overhead führen.

Ich bin mir sicher, dass ich Dinge weglasse, aber ich denke, dies sollten genug Informationen sein, um mit dem Experimentieren zu beginnen, wenn Sie weitere Details benötigen.

David
quelle
9
Der Teil a == b ist falsch. Der Operator == ist für die String-Klasse effektiv überladen und vergleicht die Werte unabhängig von den tatsächlichen Referenzen.
Goyuix