2009-09-27 3 views
14

Ich sehe ein anderes Verhalten zwischen der Verwendung von .Equals und == zwischen zwei der neuen .NET 4.0 Tuple <> Instanzen. Wenn ich im Tuple <> Equals für das Objekt überschrieben habe und .Equals für die Tuples aufrufen, wird die Override von Equals aufgerufen. Wenn ich == auf den Tupeln verwende, wird die Überschreibung von Equals nicht aufgerufen. Ist das von Entwurf und macht es Sinn?Ist dieses erwartete C# 4.0 Tuple-Gleichheitsverhalten?

EDIT: Von Antworten und Kommentare kann ich sagen, ich bin nicht klar. Ich weiß, Tupel <> ist ein Referenztyp und das für Referenztypen == wird Identität (ReferenceEquals) überprüfen. Aber sollte Tupel <> override == die Gleichheit der enthaltenen Objekte überprüfen? Aus Konsistenzgründen wahrscheinlich nicht.

Zum Beispiel, wenn ich ein einfaches Objekt

public class NameAndNumber 
{ 
    public int Number { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj is NameAndNumber) 
     { 
      NameAndNumber other = (NameAndNumber)obj; 
      return Number == other.Number && Name == other.Name; 
     } 

     return false; 
    } 
} 

haben und dann so etwas wie dies tue ich:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
bool operatorResult = left == right; 
bool equalsResult = left.Equals(right); 
Console.Out.WriteLine("operatorResult = {0} equalsResult = {1}", 
     operatorResult, equalsResult); 

I operatorResult = false equalsResult = true

Sollte ich erwartet werden erhalten Das?

Ich weiß, die Implementierung von Equals auf NameAndNumber ist nicht "richtig", es ist nur vereinfachter Beispielcode.

Ich habe auch versucht, IEquatable, ==,! =, Und GetHashCode zu implementieren. Gleiche Ergebnisse.

+0

Danke für die Antworten und Kommentare. Ich hätte dieses Verhalten erwarten sollen. Ich ersetze unsere Projekte 3.5 Tuple-Implementierung haben wir uns mit der .NET 4-Implementierung geschrieben. Unser Tupel überschreibt ==, um das erwartete Verhalten in der Frage zu erhalten. So war ich überrascht, als es sich nicht genau wie unser Gewohntes verhielt. –

Antwort

13

Die Ergebnisse, die Sie von einem design compromise kommen sehen, Tupeln jetzt geteilt zwischen F # und C#. Der Hauptpunkt ist, dass alle Tupel tatsächlich als Referenztypen implementiert sind, was nicht so offensichtlich war.

Die Entscheidung, ob Tupel tiefe oder oberflächliche Gleichheitsprüfungen durchführen sollte, wurde auf zwei Schnittstellen verschoben: IStructuralComparable, IStructuralEquatable. Beachten Sie, dass diese 2 jetzt auch von der Array-Klasse implementiert werden.

6

Für Referenztyp: == führt einen Identitätsvergleich durch, d. H. Es wird nur wahr zurückgegeben, wenn beide Referenzen auf dasselbe Objekt zeigen. Es wird erwartet, dass die Equals() - Methode einen Wertevergleich durchführt, d. H. Sie gibt true zurück, wenn die Referenzen auf Objekte zeigen, die äquivalent sind.

Für Referenztypen, bei denen == hat NICHT überlastet wurde, vergleicht sie, ob zwei Referenzen auf dasselbe Objekt verweisen

+3

Außer der Schnur, die Magie ist. Ich denke, ich suche nach mehr Magie. Würden Sie erwarten, dass ein Tupel von Werttypen eine Wertüberprüfung durchführt? Es tut es nicht. –

+5

Es gibt keine Magie - es hat einfach überladen == /! = Operatoren; Sie können dies in reflector als op_Equality und op_Inequality (on System.String) sehen. ** ** ** ist jedoch Magie auf Dinge wie "int"/"float" (definiert in der Spezifikation) und "Nullable " (die "aufgehobenen" Operatoren verwendet). –

+0

Ich bin mir nicht sicher, ob ich Ihre Kommentare vollständig verstanden habe, Ihr Tuple in Ihrem Beispielcode ist ein Referenztyp, nicht wahr? –

1

standardmäßig der Operator == Tests als Referenz Gleichheit so Ja das Ergebnis, das Sie Sehen wird erwartet.

Siehe Guidelines for Overriding Equals() and Operator == (C# Programming Guide):

In C# gibt es zwei verschiedene Arten der Gleichheit: Referenz Gleichheit (auch als Identität bekannt) und Wertgleichheit. Wertgleichheit ist die allgemein verstandene Bedeutung der Gleichheit: Sie bedeutet bedeutet, dass zwei Objekte die gleichen Werte enthalten. Zum Beispiel haben zwei Ganzzahlen mit dem Wert 2 den Wert Gleichheit. Referenzgleichheit bedeutet , dass es keine zwei Objekte zu zu vergleichen gibt.

1

Standardmäßig bedeutet == (für eine Klasse) Referenzgleichheit; d.h. sind sie die gleiche Instanz; was object.ReferenceEquals(x,y) würde zurückkehren.

Sie können Ihre eigenen == /!= Betreiber das erwartete Verhalten zu bekommen - und wenn Sie Equals außer Kraft gesetzt ist es wichtig, GetHashCode auch außer Kraft zu setzen (sonst brechen Sie die Nutzung als Schlüssel - Why is it important to override GetHashCode when Equals method is overriden in C#?):

public static bool operator == (NameAndNumber x, NameAndNumber y) { 
    if (x == null && y == null) return true; 
    if (x == null || y == null) return false; 
    return x.Number == y.Number && x.Name == y.Name; 
    // or if polymorphism is important: return x.Equals(y); 
} 
public static bool operator !=(NameAndNumber x, NameAndNumber y) { 
    return !(x == y); // lazy but works 
} 
public override int GetHashCode() { 
    return (Name == null ? 0 : Name.GetHashCode()) + 
     17 * Number.GetHashCode(); 
} 
+1

Ich weiß. Wie ich bereits erwähnt habe, habe ich eine vereinfachte Implementierung gezeigt und GetHashCode für ein kleineres Beispiel weggelassen. Aber das wird nicht ändern, wie Tuple funktioniert und ich kann diese nicht zu Tuple hinzufügen. Ich kann von Tuple ableiten und sie hinzufügen. –

+1

Wenn Polymorphismus das Problem ist, dann machen Sie das == verwenden '.Equals' - anders als das ... das ist einfach wie' == 'funktioniert. Wenn Sie es nicht überlasten, wird es nicht so funktionieren! –

+0

@Marc Gravell. Ich denke, das Herz der Frage liegt darin, ob sich die eingebaute Tuple-Klasse in .net 4.0 so verhält oder nicht. Soll es sich wie ein Standardreferenztyp verhalten oder die Gleichheitsprüfung an die darin enthaltenen Objekte delegieren? Es ist nur ein Container, also sollten wir uns darum kümmern, ob die beiden Container gleich sind oder == Überprüfen Sie den Inhalt des Containers. Dies ist nicht meine Implementierung von Tuple, es ist die eingebaute .net 4 one. Frühere Drittanbieterbibliotheken mit einer Tupel- oder Paarimplementierung würden überschreiben == die Gleichheit der enthaltenen Objekte überprüfen. –