2010-03-22 11 views
25

Ich bin heute in diese Situation geraten. Ich habe ein Objekt, das ich auf Gleichheit überprüfe; Die Create() -Methode gibt eine Unterklassenimplementierung von MyObject zurück.Wann kann a == b falsch und a.Equals (b) wahr sein?

MyObject a = MyObject.Create(); 
MyObject b = MyObject.Create(); 

a == b; // is false 
a.Equals(b); // is true 

Hinweis Ich habe auch übergegangen Equals() in der Unterklasse Implementierung, die eine sehr grundlegende Überprüfung tut, um zu sehen, ob das übergebene Objekt null ist und ist vom Typ der Unterklasse. Wenn diese beiden Bedingungen erfüllt sind, gelten die Objekte als gleich.

Das andere leicht Seltsame ist, dass meine Unit-Test-Suite hat einige Tests ähnlich wie

Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar 

und das erwartete Ergebnis beobachtet wird. Daher nehme ich an, dass NUnit a.Equals (b) unter den Deckblättern verwendet, anstatt a == b, wie ich angenommen hatte.

Seitennotiz: Ich programmiere in einer Mischung von .NET und Java, also könnte ich hier meine Erwartungen/Annahmen durcheinanderbringen. Ich dachte jedoch, dass a == b in .NET konsistenter arbeitete als in Java, wo Sie oft equals() verwenden müssen, um die Gleichheit zu testen.

UPDATE Hier ist die Implementierung von Equals(), wie gewünscht:

public override bool Equals(object obj) { 
    return obj != null && obj is MyObjectSubclass; 
} 
+3

Könnten wir Ihre Implementierung der .Equals() überschreiben – msarchet

+1

Bitte schreiben Sie den Code für die überschriebene Equals-Funktion. – AxelEckenberger

+0

wenn einer aber nicht beide natürlich überschrieben wird :) – RCIX

Antwort

32

Der wesentliche Unterschied zwischen == und Equals ist, dass == (wie alle Betreiber) nicht polymorph, während Equals (wie jede virtuelle Funktion) ist.

Standardmäßig erhalten Referenztypen identische Ergebnisse für == und Equals, da beide Referenzen vergleichen. Es ist natürlich auch möglich, Ihre Operatorlogik und Ihre Logik völlig anders zu kodieren, obwohl das nicht sinnvoll erscheint. Der größte Fehler tritt auf, wenn der Operator == (oder ein beliebiger) auf einer höheren Ebene als die gewünschte Logik verwendet wird (mit anderen Worten, das Objekt als Elternklasse referenziert, die den Operator nicht explizit definiert oder anders als den Operator definiert) wahre Klasse). In solchen Fällen wird die Logik für die Klasse, die lautet, auf wie für Operatoren verwendet, aber die Logik für Equals kommt von welcher Klasse das Objekt tatsächlich ist.

ich mit Nachdruck sagen wollen, dass in Ihrer Frage allein auf der Grundlage der Informationen, gibt es absolut keinen Grund zu glauben oder zu annehmen, dass Equals Werte im Vergleich zu Referenzen vergleicht. Es ist trivial einfach, eine solche Klasse zu erstellen, aber das ist nicht eine Sprachspezifikation.

Post-Frage-edit

Ihre Implementierung von Equals für jede Nicht-Null-Instanz der Klasse true zurück. Obwohl die Syntax mich glauben lässt, dass Sie es nicht sind, verwirren Sie möglicherweise das is C# -Schlüsselwort (das den Typ bestätigt) mit dem Schlüsselwort is in VB.NET (das die referenzielle Gleichheit bestätigt). Wenn dies tatsächlich der Fall ist, können Sie einen expliziten Referenzvergleich in C# durchführen, indem Sie Object.ReferenceEquals(this, obj) verwenden.

In jedem Fall sehen Sie deshalb true für Equals, da Sie eine Nicht-Null-Instanz Ihrer Klasse übergeben.

Übrigens ist Ihr Kommentar über NUnit mit Equals aus dem gleichen Grund wahr; Da Operatoren nicht polymorph sind, gäbe es für eine bestimmte Klasse keine Möglichkeit, benutzerdefiniertes Gleichheitsverhalten zu definieren, wenn die Assert-Funktion == verwendet.

+0

Das ist die einzige richtige Antwort bis jetzt – Lee

+4

Dies ist möglicherweise die beste Antwort, die ich je zu einer Frage hatte, die ich auf SO gestellt habe. Danke Adam, ich wünschte, ich könnte dir mehr als nur das eine Mal auffrischen! – alastairs

+1

+1 zur Adressierung der Equals-Überschreibung, nachdem das OP die Frage mit dem Code aktualisiert hat. –

6

a == b überprüft, ob sie das gleiche Objekt verweisen.

a.Equals (b) vergleicht den Inhalt.

Dies ist ein link zu einem Jon Skeet Artikel aus dem Jahr 2004, der es besser erklärt.

+1

True für Strings. Verallgemeinert für andere Klassen, liefert 'a.Equals (b)' das Ergebnis der Equals-Methode von 'a'. –

+0

Es sei denn, Sie überladen den Operator ==. +1 –

+4

-1. Es gibt absolut keinen Grund zu der Annahme, dass "Gleich" hier die Gleichheit auf der Grundlage einer gründlichen Untersuchung der Daten des Objekts bestimmt. –

0

Ich glaube, dass a == b überprüft, ob das referenzierte Objekt das gleiche ist.

Normalerweise um zu sehen, ob der Wert der gleiche ist a.Equals (b) verwendet wird (dies muss oft außer Kraft gesetzt werden, um zu arbeiten).

+1

Es sei denn, die Klasse überschreibt den Operator ==. –

+1

Das ist falsch. Es gibt keinen semantischen Sprachunterschied zwischen '==' und 'Equals'. –

1

In Java a == b überprüfen, ob die Referenzen der beiden Objekte sind gleich (rougly, sind, wenn die beiden Objekte das gleiche Objekt „Alias“)

a.equals (b) Vergleichen Sie die Werte vertreten durch die zwei Objekte.

+1

Wahr in Java, stimmt nicht immer in C#. –

0

Die Funktion "==" testet die absolute Gleichheit (außer überlastet); es testet, ob zwei Objekte das gleiche Objekt sind. Das ist nur dann der Fall, wenn Sie dem anderen einen zugewiesen haben, d.

MyObject a = MyObject.Create(); 
MyObject b = a; 

Einstellung nur alle Eigenschaften der beiden Objekte gleich, bedeutet nicht, die Objekte selbst sind. Unter der Haube vergleicht der Operator "==" die Adressen der Objekte im Speicher. Ein praktischer Effekt davon ist, dass, wenn zwei Objekte wirklich gleich sind, das Ändern einer Eigenschaft auf einer von ihnen sie auch auf der anderen ändern wird, wohingegen, wenn sie nur gleich sind ("Gleich" gleich), wird es nicht. Dies ist vollkommen konsistent, sobald Sie das Prinzip verstanden haben.

+0

Dies gilt standardmäßig * für Referenztypen *. Es ist keine absolute Wahrheit. –

1

Sie beide machen das gleiche, es sei denn, sie sind speziell im Objekt überladen, um etwas anderes zu tun.

Ein Zitat aus der Jon Skeet Article an anderer Stelle erwähnt.

Die Methode Equals ist nur ein virtuelles ein in System.Object definiert und außer Kraft gesetzt durch Unabhängig davon, welche Klassen wählen dies zu tun. Der Operator == ist ein Operator , der von Klassen überlastet werden kann, aber normalerweise Identitätsverhalten hat.

Das Schlüsselwort hier ist USUALLY. Sie können geschrieben werden, um zu tun, was auch immer die zugrunde liegende Klasse wünscht, und in keiner Weise müssen sie das Gleiche tun.

3

Sie beantwortet so ziemlich Ihre Frage selbst:

Ich habe auch übergangen Equals() in der Unterklasse Implementierung, die eine sehr grundlegende Überprüfung tut, um zu sehen, ob das übergebene Objekt null ist und ist vom Typ der Unterklasse. Wenn diese beiden Bedingungen erfüllt sind, gelten die Objekte als gleich.

Der == Betreiber überlastet nicht - so es sind false seit a und b verschiedenen Objekten ist zurück. Aber a.Equals ruft Ihre Überschreibung auf, die vermutlich true zurückgibt, weil weder a noch b null sind, und sie beide vom Typ der Unterklasse sind.

Also war Ihre Frage "Wann kann a == b falsch sein und a.Equals (b) wahr?" Ihre Antwort lautet in diesem Fall: Wenn Sie es explizit so kodieren!

+1

Als Korrekturpunkt werden Operatoren * überladen *, nicht * überschrieben * (da sie statisch sind). Es gibt keinen Polymorphismus mit Operatoren, daher wäre es immer noch trivial, ein Szenario zu erzeugen, in dem identische Logik im Operator '==' und in der Methode 'Equals' unterschiedliche Ergebnisse liefern würde. –

+0

Ok, also indem ich meine Objekte auf diese Weise codiert habe, habe ich explizit Equals/== gebrochen. Ist das ein Code-Geruch, der anzeigt, dass das Design neu denken muss? – alastairs

+0

@alastairs: Wenn Sie zwei beliebige Nicht-Null-Instanzen Ihres Typs * als gleich betrachten wollen, dann haben Sie Ihre Funktion korrekt codiert. –

Verwandte Themen