2010-12-07 5 views
9

Ich habe einige Objekte mit einer Reihe von Feldern und ich finde, dass ich GetHashCode und Equals implementieren muss. Es ist schmerzhaft zu gehen, obwohl jedes Feld manuell so dass ich sie wie folgt geschrieben:Warum sollte ich Equals und GetHashCode nicht mithilfe von Reflektion implementieren?

public override int GetHashCode() 
{ 
    int hash = 17; 
    foreach (PropertyInfo p in GetType().GetProperties()) 
    { 
     hash = hash * 23 + p.GetValue(this, null).GetHashCode(); 
    } 
    return hash; 
} 

public override bool Equals(object obj) 
{ 
    foreach (PropertyInfo p in GetType().GetProperties()) 
    { 
     if (p.GetValue(obj, null) != p.GetValue(this, null)) 
      return false; 
    } 
    return true; 
} 

Andere als die Geschwindigkeit Überlegungen, warum soll ich sie nicht umsetzen, wie das?

+0

Neben Fehlern führen würde, beachten Sie, dass nicht alle korrekte Implementierungen von "GetHashCode" und "Equals" entsprechen dem obigen Algo. Übrigens gibt es einige Probleme mit dem geposteten Code. Sie könnten "null" an mehreren Stellen dereferenzieren. Darüber hinaus verwendet Ihre Version von "Equals" die Referenzgleichheit zwischen entsprechenden Eigenschaften, was nicht das am häufigsten verwendete Idiom ist. – Ani

+0

Lustig sollten Sie fragen, es ist. – stimms

+0

Verwenden Sie ReSharper - es erzeugt korrekte Implementierungen von 'Equals' und' GetHashCode' für Sie. –

Antwort

7

Hier sind ein paar Gründe, warum ich diesen Weg

die falsche Annahme, dass zwei Objekte gelten als gleich vermeiden würde, wenn sie
  • Es ist sehr viel zuverlässiger Felder vergleichen anstelle von Eigenschaften
  • Ihr Code macht die gleiche Referenz (Sie verwenden ==). Dies ist nicht der Fall, da viele Typen die Wertgleichheit über .Equals implementieren. Es ist sehr möglich und legal, dass zwei verschiedene Referenzen als Equals betrachtet werden und Ihren Test übertreffen würden.
  • Wenn diese Form der Gleichheit weit verbreitet durch Ihre Codebasis verwendet wird, wird es sehr leicht zu unendlicher Rekursion führen, wenn der Objektgraph Zyklen hat.
  • Die GetHashCode Methode ignoriert, dass eine Eigenschaft null könnte

Im Folgenden ein konkretes Beispiel für eine Art ist, die unendliche Rekursion in Ihrer Anwendung

class C1 { 
    public object Prop1 { get; set; } 
}; 

var local = new C1(); 
local.Prop1 = local; 
var x = local.GetHashCode(); // Infinite recursion 
+0

Unendliche Rekursion ist ein sehr guter Punkt – stimms

5

Alle Werttypeigenschaften werden durch die Aufrufe GetValue eingerahmt, was bedeutet, dass sie niemals als gleichwertig angesehen werden, auch wenn sie denselben Wert haben.

Sie können dies vermeiden, indem Sie die statische Equals(x,y) Methode aufrufen - die dann mit der virtuellen x.Equals(y) Methode verschieben, wenn erforderlich - statt dem nicht-virtuellen == Operator, der in diesem Fall immer Referenz Gleichheit testen.

if (!object.Equals(p.GetValue(obj, null), p.GetValue(this, null))) 
    return false; 
+0

Typo behoben, aber! = Übrig, um deine Antwort gültig zu halten – stimms

+0

'a.Equals (b)' wird geworfen, wenn 'a'' null' ist; 'Object.Equals (a, b)' gibt 'false' zurück. –

+0

@Tim: Guter Punkt. Aktualisiert. – LukeH

2
  1. Es kann eine schlecht konditionierten Hash geben (nicht alle Eigenschaften gleich sind in Objektidentität zu bestimmen.)

  2. Wie derzeit implementiert, die Hash-Berechnung überlaufen kann.

2

Wenn Ihr Objekt gleich nur, wenn alle Eigenschaften gleich sind, dann gehen Sie vor. Aber ich bezweifle es. ZB ein Mitarbeiter ist einzigartig durch seine Mitarbeiter-ID. Wenn Sie dies tun, können Sie Änderungen an Mitarbeiterdaten nicht vergleichen.

Verwandte Themen