Prägnante Art und Weise zu kombinieren Bereich hashcodes?
Wenn die Methoden zur Implementierung von GetHashCode - wo es erforderlich ist, dies zu tun - dargestellt von Jon Skeet hier. Wiederholte seine code:
public override int GetHashCode()
{
unchecked //Overflow is fine, just wrap
{
int hash = 17;
//Suitable nullity checks etc, of course :)
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
Rollen dieser code von hand-Fehler-anfällig und Fehler können so subtil sein/schwer zu erkennen (hast du swap +
und *
durch Fehler?), es kann schwer sein, sich daran zu erinnern, die Kombination Regeln für verschiedene Arten, und ich weiß nicht, wie aufwendet, die geistige Anstrengung auf das schreiben/überprüfen Sie die gleiche Sache über und über wieder für verschiedene Felder und Klassen. Es kann auch verschleiern eines der wichtigsten details (Tat, ich erinnere mich auch an die Felder?) in sich wiederholenden Lärm.
Gibt es eine prägnante Art und Weise zu kombinieren Bereich hashcodes mit dem .net-Bibliothek?. Natürlich könnte ich schreiben, dass meine eigenen, aber wenn es etwas gibt, idiomatische/built-in, ich würde es vorziehen, dass.
Als ein Beispiel, in Java (mit JDK7) habe ich erreichen können, die oben mit Hilfe von:
@Override
public int hashCode()
{
return Objects.hash(field1, field2, field3);
}
Dies wirklich hilft bei der Beseitigung von bugs und konzentrieren sich in wichtigen details.
Motivation: ich kam in eine C# - Klasse, die eine überschrieben GetHashCode()
, aber die Art, wie es kombiniert die hashcodes der einzelnen Bestandteile hatte einige schwere bugs. Eine library-Funktion für die Kombination der hashcodes wäre nützlich für die Vermeidung von solchen Fehlern.
- Was tun Sie wollen, dass?
- Soweit ich weiß ist die nächstgelegene Sie bekommen können, ist die Verwendung von ReSharper für die Gleichstellung der Mitglieder und die hash-code-Generierung,...
- Alle Objekte in .NET implementieren
GetHashCode()
wenn Sie möchten, kombinieren Sie Sie einfach stellen, was Logik, die Sie wollen, tun Sie es mit in eine helper-Methode. - Ich will nicht schreiben ein-Helfer-Methode. Ich will, dass jemand anderes schreibt eine standard-helper-Methode. Speziell möchte ich jemand zu schreiben, eine korrekte helper-Methode, um möglichst die Chancen zu schreiben (oder einen maintainer, es zu verändern) eine falsche Umsetzung. Es ist sehr einfach zu falsch kombinieren-hashes in einer Weise, dass führt zu vielen Kollisionen.
- bist du immer noch nicht erklärt, WARUM Sie wollen, überschreiben Sie hashcode und so ein Zeug.
- es gibt viele Gründe, um überschreiben von hashcode/GetHashCode. Insbesondere, ist es empfehlenswert, wenn Sie Equals überschreiben und erforderlich, wenn Sie wollen vernünftige Verhalten, wenn Ihr Objekt einen Schlüssel in einer Hashtabelle. msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
- Hashtable war vor 8 Jahren, und Sie brauchen einen guten Grund zu überschreiben
Equals()
auch - OK, also ist die fundamentale Voraussetzung für Ihre position, dass es nur wenige Gründe, die für die meisten Entwickler zu überschreiben
GetHashCode
, und darum, dass eine Bibliothek-Funktion ist nur von begrenztem nutzen? Das ist gut/nützlich genug Ratschläge zu setzen, eine vollständige Antwort auf ein "dies ist, wie ich Dinge tun, in Java, wie mache ich es in C#" Art von Frage. - Mein Punkt ist, dass ich nicht sehen, WARUM würden Sie überschreiben
Equals()
in solch einer täglichen basis, so dass eine helper-Methode oder die Bibliothek für das. - Schulterzucken. Ich überschreiben
equals()
undhashcode()
im Java-code regelmäßig, denn Sie brauchen, wenn Sie möchten, verwenden Sie eine Klasse als hashmap Schlüssel, ohne sich auf Objekt-Identität. Vielleicht bessere Unterstützung für Werttypen in C# macht, die meist redundant (wieder, das würde für eine großartige Antwort auf die Frage). Ich fand einen buggy Umsetzung desGetHashCode()
in einigen C# - code und ich dachte, das problem wäre vermieden worden, wenn, Sie würden eine standard-library-Funktion zum kombinieren der hashcodes. - Ich schrieb einen Helfer für diese: blog.slaks.net/2010/12/...
- Meine Noda Time library überschreibt Equals/GetHashCode in über 20 Arten (oder bietet eine Gleichstellung comparer, die ist ziemlich ähnlich). Ich bin froh, dass der
HashCodeHelper
wenn es dazu kommt... - sorry, ich meinte Dictionary (Hashtable nicht) sowieso. Der Punkt immer noch gilt - es ist eine Implementierung einer hash-Tabelle (die sich auf GetHashCode -) wie auch immer, richtig?
- es war ein Klasse dienen einem ähnlichen Zweck, um Ihre ValueComparer (und in der Tat umgesetzt, in einer ähnlichen Art und Weise), dass hatte den buggy Umsetzung 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einige Leute benutzen:
Erwähnt auf der MSDN-Website unter
- Objekt.GetHashCode()
, mit der Warnung:Die Logik der Aggregation der konstituierenden hashes wird durch
System.Tuple
, die hoffentlich gehabt hat, einige Gedanken in Sie gehen...Update: es ist erwähnenswert @Ryan ' s Beobachtung in den Kommentaren, dass diese nur angezeigt wird, verwenden Sie die letzten 8 Elemente der Tupel von Größe>8.
Tuple.Create(first, second, third, fourth, fifth, sixth, seventh, Tuple.Create(eight, ninth, tenth, ...)).GetHashCode()
umzugehen?(((h1 << 5) + h1) ^ h2)
heißt auf je zwei Elemente zerlegt werden. Dann wurden jeweils zwei Ergebnisse dieser hashes Hash, bis ein hash ist am Ende übrig. Dies kann sehr teuer für große Tupel.EDIT: Stay tuned, System.HashCode kommt .NET-Kern und bieten eine einzigartige best-practice-Methode zum erstellen hashcodes. Es wird auch verwendet werden, unter der Haube vom System.Tupel und andere unveränderlich sind zusammengesetzte Typen. Bis es freigegeben wird, wird die Antwort unten ist immer noch nützlich.
Der Vollständigkeit halber, hier ist der hashing-Algorithmus, entnommen aus dem .NET-Tupels Referenz-Quelle, Linie 52. Interessant ist, dass diese hash-Algorithmus, die kopiert wurde, über die von
System.Web.Util.HashCodeCombiner
.Hier ist der code:
Natürlich die eigentlichen Tupel
GetHashCode()
(was ist eigentlich einInt32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
) hat eine großeswitch
block zu entscheiden, welche von diesen zu nennen, basiert darauf, wie viele Elemente es hält - deinen eigenen code wohl nicht verlangen, dass.Ist es nicht genau der gleiche, aber wir haben eine
HashCodeHelper
Klasse in Noda Zeit (die hat viele Arten, die überschreiben, Gleichheit und hash-code-Operationen).Man benutzt es wie folgt (entnommen aus
ZonedDateTime
):Beachten Sie, dass es eine generische Methode, die verhindert, Boxen für value-Typen. Es kommt mit null-Werten automatisch (mit 0 für den Wert). Beachten Sie, dass die
MakeHash
Methode hat eineunchecked
block als Noda-Zeit verwendet, überprüft die arithmetische als ein Projekt-setting, in der Erwägung, dass die hash-code-Berechnungen erlaubt sein sollte, zu überlaufen.public class Person
,public class BillingRepository
usw.internal static int HashAll(params object[] values) { int initialHash = Initialize(); return values.Aggregate(initialHash, Hash); }
Hier sind ein paar prägnant (wenn auch nicht so effizient) refactors der
System.Web.Util.HashCodeCombiner
erwähnt in Ryan ' s Antwort{Field1="foo",Field2="bar"}
erzeugt den gleichen hash wie{Field1="bar",Field2="foo"}
. Plus, mit ein oder eher als eine Xor-könnte man als besonders schlimm - je mehr Felder du hast, desto wahrscheinlicher, dass Sie Ihre hash ist nur gleich 0xFFFFFFFF - in der Tat, wennField1.GetHashCode()
= -1 = 0xFFFFFFFF, es ist egal, was die anderen Felder sind, werden Sie alle haben ein hashcode von 0xFFFFFF.Field1
-1 ist, werden alle anderen Felder wären überflüssig durch diese Umsetzung.return (this.Field1.GetHashCode().ToString() + this.Field2.GetHashCode().ToString()).GetHashCode();
würde eine bessere Umsetzung. 😉