2010-11-06 4 views
7

Ich habe ein Problem mit GetHashCode und Equals, die ich für eine Klasse überschrieben habe. Ich verwende den Operator ==, um zu überprüfen, ob beide gleich sind, und ich würde erwarten, dass dies sowohl GetHashCode als auch Equals aufrufen würde, wenn deren Hash-Code identisch ist, um zu bestätigen, dass sie tatsächlich gleich sind.C# GetHashCode/Equals Override nicht aufgerufen

Aber zu meiner Überraschung, werden beide nicht aufgerufen und das Ergebnis der Gleichheitsprüfung ist falsch (während es tatsächlich wahr sein sollte).

Aufhebungscode:

public class User : ActiveRecordBase<User> 

     [...] 

     public override int GetHashCode() 
     { 
      return Id; 
     } 

     public override bool Equals(object obj) 
     { 
      User user = (User)obj; 
      if (user == null) 
      { 
       return false; 
      } 

      return user.Id == Id; 
     } 
    } 

Equality-Check:

if (x == y) // x and y are both of the same User class 
    // I'd expect this test to call both GetHashCode and Equals 
+4

Wenn die '==' in der Tat hat die 'Equals' Methode aufrufen, dann würde es einen Stapelüberlauf verursachen, da sie die' == 'Operator auf dem Objekt verwendet ... – Guffa

+0

Es im Code ist nichts Sie zeigen, dass dies einen Aufruf von GetHashCode() anzeigen würde. Dies wird nur aufgerufen, wenn Sie Ihr Objekt als Schlüssel einer Sammlung verwenden. – RenniePet

Antwort

11

Operator == ist völlig unabhängig von entweder .GetHashCode() oder .Equals().

Sie könnten in der Microsoft Guidelines for Overloading Equals() and Operator == interessiert sein.

Die kurze Version ist: Verwenden Sie .Equals() zu implementieren Gleichheit Vergleiche. Verwenden Sie den Operator == für Identität Vergleiche, oder wenn Sie einen unveränderlichen Typ erstellen (wobei jede Instanz als identisch betrachtet werden kann). Außerdem ist .Equals() eine virtuelle Methode und kann von Unterklassen überschrieben werden, aber der Operator == hängt vom Kompilierungszeittyp des Ausdrucks ab, in dem er verwendet wird.

Schließlich, um konsistent zu sein, implementieren Sie .GetHashCode() zu jeder Zeit implementieren Sie .Equals(). Überlastungsoperator != jederzeit, wenn Sie den Operator == überlasten.

+0

Meine Objekte sind veränderbar. Ich erwartete, dass das Aufrufen des ==-Operators tatsächlich die Equals-Methode aufrufen würde, die ich schon vorher gesehen habe, aber ich verstehe nicht, warum es jetzt nicht funktioniert und es funktionierte vor ... – tomzx

+0

@tomzx: The '= = 'operator ruft niemals die' .Equals() 'Methode auf, wenn Sie sie nicht überladen. –

+1

@Daniel Ihr Hinweis zu "==" ist falsch. Microsoft sagt konsistent, dass Sie "ReferenceEquals" verwenden müssen, wenn Sie IDENTITY-Vergleich wünschen. Betrachten Sie beispielsweise Zeichenfolgen. Wenn Sie den Zeichenfolgengenerator verwenden, um zwei Zeichenfolgen mit demselben Inhalt, aber unterschiedlichen Adressen zu erstellen, gibt "==" TRUE (Gleichheitsvergleich) zurück, aber ReferenceEquals wird FALSE zurückgeben. "==" wird normalerweise als Vergleich der GLEICHSTELLUNG angesehen und wird normalerweise so ausgeführt, als würde man tun, was auch immer die Klasse EQUALS tut. – ToolmakerSteve

1

vielleicht Hinzufügen einer weiteren Methode in Ihrer User Klasse.

public virtual bool Equals(User other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     return other.Id == Id; 
    }