C # Unterschied zwischen == und Equals ()


548

Ich habe eine Bedingung in einer Silverlight - Anwendung , die zwei Strings vergleicht, aus irgendeinem Grund , wenn ich ==es wieder falsch während .Equals()kehrt wahr .

Hier ist der Code:

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

Gibt es einen Grund, warum dies geschieht?



8
Zeichenfolgenüberschreibungen ==, aber Operatoren sind nicht polymorph. In diesem Code wird der ==Operator für den Typ aufgerufen object, der einen Identitätsvergleich anstelle eines Werts eins durchführt.
Drew Noakes

12
So erweitern Sie den Kommentar von @DrewNoakes: Der Compiler wählt eine ==Überladung basierend auf dem Typ der Operanden zur Kompilierungszeit. Das ContentAnwesen ist object. Operatoren sind nicht virtuell, daher wird die Standardimplementierung von ==aufgerufen, um einen Vergleich der Referenzgleichheit zu ermöglichen. Bei Equals geht der Aufruf an die virtuelle Methode object.Equals(object). stringüberschreibt diese Methode und führt einen ordinalen Vergleich des Zeichenfolgeninhalts durch. Siehe msdn.microsoft.com/en-us/library/fkfd9eh8(v=vs.110).aspx und referencesource.microsoft.com/#mscorlib/system/string.cs,507 .
Phoog

6
Die Erklärung von @ phoog ist präzise. Es ist zu beachten, dass der C # -Compiler die (in diesem Fall problematische) Überladung auswählen muss , wenn die linke Seite den ==Typ objectzur Kompilierungszeit und die rechte Seite den Typ zur Kompilierungszeit hat . Es wird jedoch eine Warnung zur Kompilierungszeit ausgegeben, dass dies unbeabsichtigt sein könnte. So lesen Sie die Kompilierung-Warnungen! Um das Problem zu beheben und weiterhin zu verwenden , werfen Sie die linke Seite auf . Wenn ich mich richtig erinnere, schlägt der Warnungstext genau das vor. stringoperator ==(object, object)==string
Jeppe Stig Nielsen

1
@JeppeStigNielsen +1 für den Rat zum Lesen von Compiler-Warnungen. Noch besser: Aktivieren Sie die Option "Warnungen als Fehler", um alle zu zwingen, auf sie zu achten.
Phoog

Antworten:


429

Wenn ==es für einen Ausdruck vom Typ verwendet wird object, wird es in aufgelöst System.Object.ReferenceEquals.

Equalsist nur eine virtualMethode und verhält sich so, daher wird die überschriebene Version verwendet (die für den stringTyp den Inhalt vergleicht).


56
Es sei denn, der Operator ist speziell in der Klasse implementiert
Dominic Cronin

23
@ DominicCronin Das stimmt nicht. Selbst wenn == in der Klasse implementiert ist, wird es ignoriert, da der Typ links vom Vergleich Objekt ist. Es sieht so aus, als ob Operatorüberladungen zur Kompilierungszeit ermittelt werden und zur Kompilierungszeit nur bekannt ist, dass die linke Seite ein Objekt ist.
MikeKulls

4
@DominicCronin Ich glaube, Ihre erste Aussage ist insofern korrekt, als == in Objekt aufgelöst wird, Ihre zweite Aussage, die Operatorüberladungen auf ähnliche Weise auflösen, jedoch nicht. Sie sind sehr unterschiedlich, weshalb .Equals in String aufgelöst wird, während == in Objekt aufgelöst wird.
MikeKulls

8
Um klar zu sein, ist objectTyp (beachten Sie die Monospace-Schriftart) technisch als "Ausdruck des Typs System.Object" gedacht . Es hat nichts mit dem Laufzeittyp der Instanz zu tun, auf die der Ausdruck verweist. Ich denke, die Aussage "Benutzerdefinierte Operatoren werden wie virtualMethoden behandelt " ist äußerst irreführend. Sie werden wie überladene Methoden behandelt und hängen nur vom Kompilierungszeittyp der Operanden ab. Nachdem der Satz von benutzerdefinierten Operatorenkandidaten berechnet wurde, ist der Rest der Bindungsprozedur genau der Algorithmus zur Auflösung der Methodenüberladung
Mehrdad Afshari,

4
@DominicCronin Der irreführende Teil ist, dass die virtualMethodenauflösung vom tatsächlichen Laufzeittyp einer Instanz abhängt, während dies bei der Auflösung von Operatorüberlastungen völlig ignoriert wird, und das ist in der Tat der springende Punkt meiner Antwort.
Mehrdad Afshari

314

Beim Vergleichen einer Objektreferenz mit einer Zeichenfolge (auch wenn sich die Objektreferenz auf eine Zeichenfolge bezieht) wird das spezielle Verhalten des ==für die Zeichenfolgenklasse spezifischen Operators ignoriert.

Normalerweise (wenn es sich nicht um Zeichenfolgen handelt) werden WerteEquals verglichen , während Objektreferenzen verglichen werden . Wenn sich zwei Objekte, die Sie vergleichen, auf dieselbe exakte Instanz eines Objekts beziehen, geben beide true zurück. Wenn jedoch eines denselben Inhalt hat und aus einer anderen Quelle stammt (eine separate Instanz mit denselben Daten), wird nur Equals verwendet return true. Wie in den Kommentaren erwähnt, ist die Zeichenfolge jedoch ein Sonderfall, da sie den Operator überschreibt , sodass beim reinen Umgang mit Zeichenfolgenreferenzen (und nicht mit Objektreferenzen) nur die Werte verglichen werden, selbst wenn es sich um separate Instanzen handelt. Der folgende Code veranschaulicht die subtilen Unterschiede im Verhalten:====

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Die Ausgabe ist:

True True True
False True True
False False True

8
Genau richtig. Der Operator '==' vergleicht Objektreferenzen (flacher Vergleich), während .Equals () den Objektinhalt vergleicht (tiefer Vergleich). Wie @mehrdad sagte, wird .Equals () überschrieben, um diesen umfassenden Inhaltsvergleich zu ermöglichen.
Andrew

1
Ich werde den Beitrag hier lassen, weil ich denke, dass es wertvoll ist, zu betonen, was nicht passiert, da man genau darauf achten muss, um es zu realisieren. (Und ich denke, der Code, um das richtige und falsche Verständnis zu demonstrieren, lohnt sich auch.) Ich hoffe, die Bewertung wird nicht unter 0 fallen.
BlueMonkMN

5
Sicherlich implementiert String einen benutzerdefinierten == Operator. Wenn dies nicht der Fall wäre, würde die Verwendung von == den Inhalt nicht vergleichen. Daher ist String ein schlechtes Beispiel, da es uns nicht hilft, den allgemeinen Fall zu verstehen, in dem kein benutzerdefinierter Operator definiert wurde.
Dominic Cronin

6
+1 für das epische Codebeispiel, das mir Sinn machte. Zeigt den allgemeinen Fall, dass der statische Typ (linker Seitentyp) ein Objekt ist, und den speziellen Fall, dass der statische Typ (/ RHS-Typ) eine Zeichenfolge ist. Und berührt gut das Saiteninternieren.
Barlop

2
@ Badsamaritan Wegen String Interning
Alexander Derck

46

==und .Equalssind sowohl abhängig vom im tatsächlichen Typ definierten Verhalten als auch vom tatsächlichen Typ am Anrufort. Beides sind nur Methoden / Operatoren, die für jeden Typ und jedes vom Autor gewünschte Verhalten überschrieben werden können. Nach meiner Erfahrung ist es üblich, dass Benutzer .Equalsein Objekt implementieren, den Operator jedoch nicht implementieren ==. Dies bedeutet, dass .Equalstatsächlich die Gleichheit der Werte ==gemessen wird, während gemessen wird, ob es sich um dieselbe Referenz handelt oder nicht.

Wenn ich mit einem neuen Typ arbeite, dessen Definition im Fluss ist, oder generische Algorithmen schreibe, finde ich die folgende Best Practice

  • Wenn ich Referenzen in C # vergleichen möchte, verwende ich Object.ReferenceEqualsdirekt (im generischen Fall nicht erforderlich)
  • Wenn ich Werte vergleichen möchte, verwende ich EqualityComparer<T>.Default

In einigen Fällen, wenn ich der Meinung bin, dass die Verwendung von nicht ==eindeutig ist, verwende ich explizit Object.ReferenceGleichheiten im Code, um die Mehrdeutigkeit zu beseitigen.

Eric Lippert hat kürzlich einen Blog-Beitrag zum Thema verfasst, warum es in der CLR zwei Methoden der Gleichstellung gibt. Es ist die Lektüre wert


Nun, Jared, Sie verletzen direkt Jeffs berühmtes "Der beste Code ist hier überhaupt kein Code." Ist das wirklich gerechtfertigt? Andererseits kann ich sehen, woher dies stammt und warum es wünschenswert sein könnte, die Semantik explizit zu machen. In diesem Fall bevorzuge ich die Art und Weise, wie VB mit Objektgleichheit umgeht. Es ist kurz und eindeutig.
Konrad Rudolph

@Konrad, ich hätte wirklich sagen sollen: "Wenn ich mit einem Typ nicht vertraut bin, finde ich, dass die beste Vorgehensweise die folgende ist." Ja, VB hat hier eine viel bessere Semantik, weil es Wert und Referenzgleichheit wirklich trennt. C # mischt die beiden zusammen und verursacht gelegentlich Mehrdeutigkeitsfehler.
JaredPar

10
Dies ist nicht ganz richtig. == kann nicht überschrieben werden, es ist eine statische Methode. Es kann nur überladen werden, was ein wichtiger Unterschied ist. Der Code, der für einen == -Operator ausgeführt wird, wird also zur Kompilierungszeit verknüpft, während Equals virtuell ist und zur Ausführungszeit gefunden wird.
Stefan Steinegger

20

== Operator

  1. Wenn Operanden Werttypen und deren Werte sind gleich sind, gibt es wahr , sonst falsch.
  2. Wenn Operanden Referenztypen mit Ausnahme der Zeichenfolge sind und beide auf dieselbe Instanz verweisen (dasselbe Objekt) , wird true zurückgegeben, andernfalls false.
  3. Wenn Operanden vom Typ String sind und ihre Werte gleich sind, wird true zurückgegeben, andernfalls false.

Gleichungen

  1. Wenn Operanden Referenztypen sind , wird die Referenzgleichheit ausgeführt. Wenn sich beide auf dieselbe Instanz (dasselbe Objekt) beziehen , wird true zurückgegeben, andernfalls false.
  2. Wenn Operanden sind Werttypen dann anders als Operator == es prüft , ob ihre Art erste und wenn ihre Typen sind die gleichen sie führt Operator == sonst falsch er zurückkehrt.

2
Das ist nicht richtig. Der ==Operator kann für jeden Typ überladen werden, nicht nur für Zeichenfolgen. Das Beschreiben einer Sonderfallausnahme nur für Zeichenfolgen stellt die Semantik des Operators falsch dar. Es wäre genauer, wenn auch nicht besonders nützlich zu sagen: "Wenn Operanden Referenztypen sind, gibt sie true zurück, wenn sich die Operanden auf dasselbe Objekt beziehen, es sei denn, es liegt eine anwendbare Überladung vor. In diesem Fall bestimmt die Implementierung dieser Überladung das Ergebnis." ". Gleiches gilt für Equalsdie zusätzliche Komplikation, dass es sich um eine virtuelle Methode handelt, sodass ihr Verhalten sowohl überschrieben als auch überladen werden kann.
Phoog

19

Erstens gibt es einen Unterschied. Für Zahlen

> 2 == 2.0
True

> 2.Equals(2.0)
False

Und für Streicher

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

In beiden Fällen ==verhält sich nützlicher als.Equals


2
Ich bin mir nicht sicher, ob ich das Erzwingen von Integraltypen zu Gleitkommatypen mit dem ==Operator als eine gute Sache betrachten würde. Sollte beispielsweise 16777216.0f gleich (int) 16777217, (doppelt) 16777217.0, beide oder keine sein? Vergleiche zwischen integralen Typen sind in Ordnung, aber Gleitkomma-Vergleiche sollten IMHO nur mit Werten durchgeführt werden, die explizit in übereinstimmende Typen umgewandelt werden. Der Vergleich von a floatmit etwas anderem als a floatoder a doublemit etwas anderem als a doublescheint mir ein wichtiger Codegeruch zu sein, der ohne Diagnose nicht kompiliert werden sollte.
Supercat

1
@supercat Ich stimme zu - es ist beunruhigend, was x == ynicht bedeutet x/3 == y/3(versuchen x = 5und y = 5.0).
Colonel Panic

Ich betrachte die Verwendung von /für die Ganzzahldivision als einen Fehler im Design von C # und Java. Pascals divund sogar VB.NETs ` are much better. The problems with == `sind jedoch schlimmer:x==y und y==zimplizieren das nicht x==z(betrachten Sie die drei Zahlen in meinem vorherigen Kommentar). Was die Beziehung betrifft, die Sie vorschlagen, selbst wenn xund ybeide floatoder beide sind double, x.equals((Object)y)bedeutet dies nicht, dass 1.0f/x == 1.0f / y` (wenn ich meine Druthers hätte, würde dies dies garantieren; auch wenn ==nicht zwischen positiv und null unterschieden wird, Equalssollte).
Supercat

Das ist normal, denn der erste Parameter von Equals () ist eine Zeichenfolge!
Schleudertrauma

17

Soweit ich es verstehe, ist die Antwort einfach:

  1. == vergleicht Objektreferenzen.
  2. .Equals vergleicht den Objektinhalt.
  3. String Datentypen verhalten sich immer wie ein Inhaltsvergleich.

Ich hoffe ich bin richtig und es hat deine Frage beantwortet.


15

Ich würde hinzufügen, dass wenn Sie Ihr Objekt in eine Zeichenfolge umwandeln, es korrekt funktioniert. Aus diesem Grund gibt der Compiler eine Warnung aus:

Möglicher unbeabsichtigter Referenzvergleich; Um einen Wertevergleich zu erhalten, geben Sie auf der linken Seite 'string' ein.


1
Genau. @DominicCronin: Beachten Sie immer die Warnungen zur Kompilierungszeit. Wenn dies der Fall ist, muss der Compiler die Überladung verwenden object expr = XXX; if (expr == "Energy") { ... }, da die linke Seite vom Typ objectKompilierungszeit ist operator ==(object, object). Es prüft auf Referenzgleichheit. Ob dies aufgrund der String-Internierung gegeben isttrue oder falseschwer vorherzusagen ist . Wenn Sie wissen, dass die linke Seite entweder vom Typ oder vom Typ ist , werfen Sie die linke Seite vor der Verwendung auf . nullstringstring==
Jeppe Stig Nielsen

einen Teil davon anders auszudrücken. == (bei der Bestimmung, ob Referenzgleichheit oder Wertgleichheit verwendet wird) hängt vom Kompilierungszeittyp / statischen Typ / Typ auf der linken Seite ab. (Dies ist der Typ, der in einer Kompilierungszeitanalyse aufgelöst wird.) Anstelle des Laufzeittyps / dynamischen Typs / RHS-Typs. Der Code von BlueMonkMN zeigt dies, allerdings nicht beim Casting.
Barlop

5

Da die statische Version der .EqualMethode bisher nicht erwähnt wurde, möchte ich diese hier hinzufügen, um die 3 Variationen zusammenzufassen und zu vergleichen.

MyString.Equals("Somestring"))          //Method 1
MyString == "Somestring"                //Method 2
String.Equals("Somestring", MyString);  //Method 3 (static String.Equals method) - better

wo MyString ist eine Variable, die von irgendwo anders im Code kommt.

Hintergrundinfo und zum Sommer:

In Java sollte die Verwendung ==zum Vergleichen von Zeichenfolgen nicht verwendet werden. Ich erwähne dies für den Fall, dass Sie beide Sprachen verwenden müssen und dass Sie dies auch wissen müssen== in C # auch durch etwas Besseres ersetzt kann.

In C # gibt es keinen praktischen Unterschied für den Vergleich von Zeichenfolgen mit Methode 1 oder Methode 2, solange beide vom Typ Zeichenfolge sind. Wenn jedoch einer null ist, einer von einem anderen Typ ist (wie eine Ganzzahl) oder einer ein Objekt darstellt, das eine andere Referenz hat, kann es sein, dass der Vergleich des Inhalts auf Gleichheit möglicherweise nicht das zurückgibt, was die erste Frage zeigt du erwartest.

Vorgeschlagene Lösung:

Da die Verwendung ==nicht genau mit der Verwendung .Equalsbeim Vergleichen von Dingen identisch ist , können Sie stattdessen die statische String.Equals- Methode verwenden. Auf diese Weise vergleichen Sie den Inhalt, wenn die beiden Seiten nicht vom selben Typ sind, und wenn eine Null ist, vermeiden Sie die Ausnahme.

   bool areEqual = String.Equals("Somestring", MyString);  

Es ist etwas mehr zu schreiben, aber meiner Meinung nach sicherer zu verwenden.

Hier sind einige Informationen, die von Microsoft kopiert wurden:

public static bool Equals (string a, string b);

Parameter

a String

Die erste zu vergleichende Zeichenfolge, oder null.

b String

Die zweite zu vergleichende Zeichenfolge oder null .

Kehrt zurück Boolean

truewenn der Wert von ader gleiche ist wie der Wert von b; sonst , false. Wenn beides aund bsind null, gibt die Methode zurück true.


5

Nur als Ergänzung zu den bereits guten Antworten: Dieses Verhalten ist NICHT auf Strings oder den Vergleich verschiedener Zahlentypen beschränkt. Auch wenn beide Elemente vom Typ Objekt desselben zugrunde liegenden Typs sind. "==" wird nicht funktionieren.

Der folgende Screenshot zeigt die Ergebnisse des Vergleichs zweier Objektwerte {int}

Beispiel aus VS2017


2

Ich bin hier etwas verwirrt. Wenn der Laufzeittyp von Content vom Typ string ist, sollten sowohl == als auch Equals true zurückgeben. Da dies jedoch nicht der Fall zu sein scheint, ist der Inhaltstyp zur Laufzeit keine Zeichenfolge, und das Aufrufen von Equals führt zu einer referenziellen Gleichheit. Dies erklärt, warum Equals ("Energy Attack") fehlschlägt. Im zweiten Fall wird jedoch zur Kompilierungszeit die Entscheidung getroffen, welcher überladene == statische Operator aufgerufen werden soll, und diese Entscheidung scheint == (Zeichenfolge, Zeichenfolge) zu sein. Dies legt für mich nahe, dass Content eine implizite Konvertierung in einen String bietet.


2
Sie haben es von hinten nach vorne. Für den Anfang schlägt Equals ("Energy Attack") nicht fehl, == ist derjenige, der false zurückgibt. Das == schlägt fehl, weil es das == from-Objekt verwendet, nicht die Zeichenfolge.
MikeKulls

Standardmäßig prüft der Operator == die Referenzgleichheit, indem er ermittelt, ob zwei Referenzen dasselbe Objekt angeben. Daher müssen Referenztypen den Operator == nicht implementieren, um diese Funktionalität zu erhalten. Wenn ein Typ unveränderlich ist, dh die in der Instanz enthaltenen Daten nicht geändert werden können, kann das Überladen des Operators == zum Vergleichen der Wertgleichheit anstelle der Referenzgleichheit nützlich sein, da sie als unveränderliche Objekte als gleich lange betrachtet werden können da sie den gleichen Wert haben. Es ist keine gute Idee, operator == in nicht unveränderlichen Typen zu überschreiben.
Wajeed-MSFT

2

Eine frühere Antwort von @BlueMonkMN hat eine andere Dimension. Die zusätzliche Dimension ist, dass die Antwort auf die Titelfrage von @ Drahcir, wie angegeben, auch davon abhängt, wie wir zu dem stringWert gekommen sind. Um zu zeigen:

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;
string s5 = "te" + "st";
object s6 = s5;
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s2), s1 == s2, s1.Equals(s2));

Console.WriteLine("\n  Case1 - A method changes the value:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s3), s1 == s3, s1.Equals(s3));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s4), s1 == s4, s1.Equals(s4));

Console.WriteLine("\n  Case2 - Having only literals allows to arrive at a literal:");
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s5), s1 == s5, s1.Equals(s5));
Console.WriteLine("{0} {1} {2}", object.ReferenceEquals(s1, s6), s1 == s6, s1.Equals(s6));

Die Ausgabe ist:

True True True

  Case1 - A method changes the value:
False True True
False False True

  Case2 - Having only literals allows to arrive at a literal:
True True True
True True True

2

Hinzufügen eines weiteren Punktes zur Antwort.

.EqualsTo() Methode bietet Ihnen die Möglichkeit, mit Kultur und Groß- und Kleinschreibung zu vergleichen.


0

Das ==Token in C # wird für zwei verschiedene Gleichheitsprüfungsoperatoren verwendet. Wenn der Compiler auf dieses Token stößt, prüft er, ob einer der verglichenen Typen eine Überladung des Gleichheitsoperators für die zu vergleichenden spezifischen Kombinationstypen (*) oder für eine Kombination von Typen implementiert hat, in die beide Typen konvertiert werden können. Wenn der Compiler eine solche Überlastung feststellt, wird er diese verwenden. Andernfalls betrachtet der Compiler ==einen Referenzvergleichsoperator , wenn die beiden Typen beide Referenztypen sind und keine nicht verwandten Klassen sind (entweder eine Schnittstelle oder verwandte Klassen) . Wenn keine der beiden Bedingungen zutrifft, schlägt die Kompilierung fehl.

Beachten Sie, dass einige andere Sprachen separate Token für die beiden Gleichheitsprüfungsoperatoren verwenden. In VB.NET wird das =Token beispielsweise in Ausdrücken ausschließlich für den überladbaren Gleichheitsprüfungsoperator Isverwendet und als Referenztest- oder Nulltestoperator verwendet. Eine Verwendung =für einen Typ, der den Gleichheitsprüfungsoperator nicht überschreibt, schlägt fehl, ebenso wie der Versuch, sie Isfür einen anderen Zweck als das Testen der Referenzgleichheit oder der Nichtigkeit zu verwenden.

(*) Typen überladen im Allgemeinen nur die Gleichheit zum Vergleich mit sich selbst, aber es kann für Typen nützlich sein, den Gleichheitsoperator zum Vergleich mit anderen bestimmten Typen zu überladen. hätte zum Beispiel inteinen Gleichheitsoperator zum Vergleich mit definieren können (und IMHO hätte dies tun sollen, aber nicht) float, so dass sich 16777217 nicht gleich 16777216f melden würde. Wie es ist, da eine solche Operator definiert ist, wird C # die Förderung intauf float, um es zu 16777216f Runden vor dem Gleichheitsprüfung Bediener es sieht; Dieser Operator sieht dann zwei gleiche Gleitkommazahlen und meldet sie als gleich, ohne die Rundung zu kennen, die stattgefunden hat.


Anstatt dass ein Int-to-Float-Vergleich false zurückgibt, bevorzuge ich den Ansatz, den F # verwendet, nämlich einen solchen Vergleich überhaupt nicht zuzulassen. Dann kann der Programmierer entscheiden, ob und wie mit der Tatsache umgegangen werden soll, dass die Werte einen anderen Typ haben. Denn manchmal wollen wir doch3 gleich behandeln 3.0f. Wenn der Programmierer in jedem Fall angeben muss, was beabsichtigt ist, besteht keine Gefahr, dass das Standardverhalten zu unbeabsichtigten Ergebnissen führt, da kein Standardverhalten vorliegt.
Phoog

@phoog: Mein persönliches Gefühl ist, dass Sprachen mit ihren "normalen" Mitteln zur Prüfung der Gleichheit eine Äquivalenzbeziehung implementieren und alle Kombinationen von Operanden verbieten sollten, für die dies nicht der Fall wäre. Ich sehe keinen großen Vorteil darin, eine Sprachprüfungsgleichheit zwischen ganzen Zahlen und Gleitkommazahlen zu haben, indem bestätigt wird, dass ein Gleitkomma genau eine ganze Zahl darstellt, die mit dem int übereinstimmt, anstatt solche Vergleiche einfach zu verbieten, aber ich würde beide Ansätze als überlegen betrachten, wenn die Sprache ausgeführt wird eine verlustbehaftete Umwandlung vor dem Vergleich.
Supercat

0

Wirklich tolle Antworten und Beispiele!

Ich möchte nur den grundlegenden Unterschied zwischen den beiden hinzufügen,

Operatoren wie ==sind nicht polymorph, während es Equalsist

Unter Berücksichtigung dieses Konzepts erhalten Sie mit Sicherheit die richtige Antwort, wenn Sie ein Beispiel ausarbeiten (indem Sie den Referenztyp für die linke und rechte Hand betrachten und prüfen / wissen, ob der Typ tatsächlich == Operator überladen und Equals überschrieben hat) .



-2

==

Der Operator == kann verwendet werden, um zwei Variablen beliebiger Art zu vergleichen, und vergleicht einfach die Bits .

int a = 3;
byte b = 3;
if (a == b) { // true }

Hinweis: Auf der linken Seite des Int befinden sich weitere Nullen, aber das interessiert uns hier nicht.

int a (00000011) == Byte b (00000011)

Denken Sie daran, dass der Operator == sich nur um das Muster der Bits in der Variablen kümmert.

Use == Wenn zwei Referenzen (Grundelemente) auf dasselbe Objekt auf dem Heap verweisen.

Die Regeln sind gleich, unabhängig davon, ob die Variable eine Referenz oder ein Grundelement ist.

Foo a = new Foo();
Foo b = new Foo();
Foo c = a;

if (a == b) { // false }
if (a == c) { // true }
if (b == c) { // false }

a == c ist wahr a == b ist falsch

Das Bitmuster ist für a und c gleich, daher sind sie mit == gleich.

Gleich():

Verwenden Sie die Methode equals (), um festzustellen, ob zwei verschiedene Objekte gleich sind .

Zum Beispiel zwei verschiedene String-Objekte, die beide die Zeichen in "Jane" darstellen.


2
Das ist falsch. Beachten Sie Folgendes : object a = 3; object b = 3; Console.WriteLine(a == b);. Die Ausgabe ist falsch, obwohl die Bitmuster der Werte gleich sind. Die Arten der Operanden spielen ebenfalls eine Rolle. Der Grund, warum uns die unterschiedliche Anzahl von Nullen in Ihrem Beispiel "egal" ist, ist, dass zum Zeitpunkt des Aufrufs des Gleichheitsoperators die Anzahl der Nullen aufgrund der impliziten Konvertierung tatsächlich gleich ist.
Phoog

-2

Der einzige Unterschied zwischen Equal und == besteht im Objekttypvergleich. In anderen Fällen, z. B. bei Referenztypen und Werttypen, sind sie nahezu gleich (entweder sind beide bitweise Gleichheit oder beide sind Referenzgleichheit).

Objekt: Gleich: bitweise Gleichheit ==: Referenzgleichheit

Zeichenfolge: (gleich und == sind für Zeichenfolge gleich, aber wenn eine der Zeichenfolgen in Objekt geändert wird, ist das Vergleichsergebnis unterschiedlich.) Gleich: bitweise Gleichheit ==: bitweise Gleichheit

Sehen Sie hier für weitere Erklärung.


Object.Equals betrachtet nicht unbedingt die bitweise Gleichheit. Es ist eine virtuelle Methode, und ein Override kann tun, was er will.
Phoog

Ja, Sie haben Recht, Sie können alles tun, um es zu überschreiben. Das Thema, über das wir sprechen, ist jedoch die Standardimplementierung. Die Standardimplementierung von Object.Equals ist die bitweise Gleichheit.
Will Yu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.