1670 Stimmen

Warum ist es wichtig, GetHashCode zu überschreiben, wenn die Methode Equals überschrieben wird?

Gegeben die folgende Klasse

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null) 
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

Ich habe die Equals Methode, weil Foo stellen eine Zeile für die Foo s Tisch. Welches ist die bevorzugte Methode zum Überschreiben der GetHashCode ?

Warum ist es wichtig, die GetHashCode ?

44voto

huha Punkte 3552

Vergessen Sie bitte nicht, den Parameter obj mit null beim Überschreiben Equals() . Und vergleichen Sie auch den Typ.

public override bool Equals(object obj)
{
    Foo fooItem = obj as Foo;

    if (fooItem == null)
    {
       return false;
    }

    return fooItem.FooId == this.FooId;
}

Der Grund dafür ist: Equals muss beim Vergleich mit null . Siehe auch http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

21voto

BornToCode Punkte 8577

Nur um die obigen Antworten zu ergänzen:

Wenn Sie Equals nicht überschreiben, ist das Standardverhalten, dass Referenzen der Objekte verglichen werden. Dasselbe gilt für Hashcode - die Standard-Implmentierung basiert typischerweise auf einer Speicheradresse der Referenz. Da Sie Equals überschrieben haben, bedeutet dies, dass das korrekte Verhalten darin besteht, das zu vergleichen, was Sie auf Equals implementiert haben, und nicht die Referenzen, also sollten Sie dasselbe für den Hashcode tun.

Clients Ihrer Klasse werden erwarten, dass der Hashcode eine ähnliche Logik wie die equals-Methode hat, z.B. linq-Methoden, die einen IEqualityComparer verwenden, vergleichen zuerst die Hashcodes und nur wenn sie gleich sind, vergleichen sie die Equals()-Methode, die möglicherweise teurer ist, wenn wir den Hashcode nicht implementiert haben, werden gleiche Objekte wahrscheinlich unterschiedliche Hashcodes haben (weil sie unterschiedliche Speicheradressen haben) und werden fälschlicherweise als nicht gleich bestimmt (Equals() wird nicht einmal getroffen).

Abgesehen von dem Problem, dass Sie Ihr Objekt möglicherweise nicht finden können, wenn Sie es in einem Wörterbuch verwenden (weil es durch einen Hashcode eingefügt wurde und wenn Sie danach suchen, wird der Standard-Hashcode wahrscheinlich ein anderer sein und wiederum wird Equals() nicht einmal aufgerufen, wie Marc Gravell in seiner Antwort erklärt, führen Sie auch eine Verletzung des Wörterbuch- oder Hashset-Konzepts ein, das keine identischen Schlüssel zulassen sollte - Sie haben bereits deklariert, dass diese Objekte im Wesentlichen gleich sind, wenn Sie Equals überschreiben, also wollen Sie nicht, dass beide als unterschiedliche Schlüssel in einer Datenstruktur verwendet werden, die einen eindeutigen Schlüssel haben soll. Da sie aber einen unterschiedlichen Hashcode haben, wird der "gleiche" Schlüssel als ein anderer eingefügt.

19voto

kemiller2002 Punkte 110605

Das liegt daran, dass das Framework verlangt, dass zwei gleiche Objekte den gleichen Hashcode haben müssen. Wenn Sie die equals-Methode überschreiben, um einen speziellen Vergleich zwischen zwei Objekten durchzuführen, und die beiden Objekte von der Methode als gleich angesehen werden, dann muss auch der Hashcode der beiden Objekte der gleiche sein. (Wörterbücher und Hashtabellen beruhen auf diesem Prinzip).

15voto

Ian Ringrose Punkte 50437

Wir haben zwei Probleme zu bewältigen.

  1. Sie können keine vernünftige GetHashCode() wenn ein Feld in der Datei Objekt geändert werden kann. Außerdem wird ein Objekt oft NIE in einer Sammlung verwendet, die von GetHashCode() . Daher sind die Kosten für Implementierung von GetHashCode() sich oft nicht lohnt, oder es ist nicht möglich.

  2. Wenn jemand Ihr Objekt in eine Sammlung aufnimmt, die GetHashCode() und Sie haben sich über die Equals() ohne auch GetHashCode() sich korrekt verhalten, kann diese Person Tage damit verbringen um das Problem aufzuspüren.

Deshalb tue ich das standardmäßig.

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null)
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}

11voto

Maciej Punkte 7601

Hash-Code wird für hashbasierte Sammlungen wie Dictionary, Hashtable, HashSet usw. verwendet. Der Zweck dieses Codes ist es, ein bestimmtes Objekt sehr schnell vorzusortieren, indem es in eine bestimmte Gruppe (Bucket) eingeordnet wird. Diese Vorsortierung hilft enorm beim Auffinden des Objekts, wenn Sie es aus der Hash-Sammlung zurückholen müssen, da der Code nur in einem Bucket nach dem Objekt suchen muss, anstatt in allen darin enthaltenen Objekten. Je besser die Hash-Codes verteilt sind (bessere Eindeutigkeit), desto schneller ist der Abruf. Im Idealfall, wenn jedes Objekt einen eindeutigen Hash-Code hat, ist das Auffinden des Objekts eine O(1)-Operation. In den meisten Fällen nähert sie sich O(1).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X