J'essaye de créer une méthode de hashcode. J'ai un code comme ci-dessous:
private static object GetValue<T>(object item, string propertyName) { ParameterExpression arg = Expression.Parameter(item.GetType(), "x"); Expression expr = Expression.Property(arg, propertyName); UnaryExpression unaryExpression = Expression.Convert(expr, typeof(object)); var propertyResolver = Expression.Lambda<Func<T, object>>(unaryExpression, arg).Compile(); return propertyResolver((T)item); } private static int GetHashCode<T>(T obj, List<string> columns) { unchecked { int hashCode = 17; for (var i = 0; i < columns.Count; i++) { object value = GetValue<T>(obj, columns[i]); var tempHashCode = value == null ? 0 : value.GetHashCode(); hashCode = (hashCode * 23) + tempHashCode; } return hashCode; } } private static void TestHashCode() { var t1 = new { ID = (long)2044716, Type = "AE", Method = (short)1022, Index = 3 }; var t2 = new { ID = (long)12114825, Type = "MEDAPE", Method = (short)1700, Index = 2 }; var e1 = t1.GetHashCode(); var e2 = t2.GetHashCode(); var columns = new[] { "ID", "Type", "Method", "Index" }.ToList(); var k1 = GetHashCode(t1, columns); var k2 = GetHashCode(t2, columns); }
La valeur e1 est -410666035, la valeur e2 est 101205027. La valeur k1 est 491329214. La valeur k2 est 491329214.
Étapes du HashCode:
hashCode = 17
tempHashCode = 2044716
hashcode = 2045107
tempHashCode = 1591023428
hashcode = 1638060889
tempHashCode = 66978814
hashcode = -912326403
tempHashCode = 3
hashcode = 491329214
Comment k1 et k2 peuvent-ils avoir la même valeur? Parce que la méthode par défaut .net gethashcode donne deux valeurs différentes. Je veux créer une méthode de hashcode qui peut obtenir une liste de colonnes. Je veux créer un code de hachage par des propriétés particulières. J'essaie d'obtenir une valeur unique pour un objet par des propriétés particulières.
Comment puis-je identifier un objet par des propriétés particulières si GetHashCode ne garantit pas une valeur unique?
3 Réponses :
Je soupçonne que le problème est causé par value.GetHashCode ()
dans votre méthode GetHashCode
. Cette variable de valeur est un objet là-bas, je pense que GetHashCode ()
ne renvoie pas ce que vous attendez. Essayez de déboguer pour savoir ce qui se passe.
Vous pouvez essayer de conserver votre code, mais au lieu de Object.GetHashCode ()
, utilisez RuntimeHelpers.GetHashCode ()
(à partir de l'espace de noms System. Runtime.CompilerServices
).
Bonne chance!
GetHashCode
renvoie une valeur qui dépend de l'implémentation. Sa conception particulière convient à l'utilisation "standard" et n'a de sens que pendant la durée de vie d'une application. L'algorithme par défaut n'est pas conçu pour éviter les collisions.
La méthode GetHashCode
n'est pas conçue pour être unique pour chaque instance.
Votre approche repose sur la composition du hachage de chaque colonne. Un code de hachage doit satisfaire certaines exigences, par exemple la distribution dans le domaine. Cependant, il n'est pas garanti que la composition préserve ces propriétés et exigences: plus vous ajoutez de colonnes, plus les collisions pourraient être "étranges".
De plus, vous invoquez value.GetHashCode ()
qui empêche une opération de boxe. Comme suggéré par johey, vous devez utiliser la méthode RuntimeHelpers.GetHashCode ()
car elle interprète l'objet comme une valeur avant de calculer le hachage.
Les structures de données .NET sont conçues pour gérer les collisions en interne, par exemple, IDictionary
utilise le hachage pour sélectionner un compartiment, puis analyse séquentiellement le compartiment.
Je veux écrire ici ma solution. Tout ce qui a été dit est vrai mais pas exactement. Je veux collecter le sujet ici.
GetHashCode
donne toujours la même valeur pour les objets identiques.
Les valeurs de GetHashCode
peuvent toujours ne pas appartenir aux différents objets.
Les valeurs de GetHashCode
sont donc d'abord comparées pour améliorer les performances, puis passez à l'étape suivante pour comparer des objets s'il y a la même valeur de GetHashCode
.
J'ai créé un IEqualityComparer.
private class CustomEqualityComparer<T> : IEqualityComparer<T> { private readonly List<string> _columns; private readonly bool _enableHashCode; private readonly ConcurrentDictionary<string, Func<T, object>> _cache; public CustomEqualityComparer(List<string> columns, ConcurrentDictionary<string, Func<T, object>> cache, bool enableHashCode = false) { _columns = columns; _enableHashCode = enableHashCode; _cache = cache; } public bool Equals(T x, T y) { for (var i = 0; i < _columns.Count; i++) { object value1 = GetValue(x, _columns[i], _cache); object value2 = GetValue(y, _columns[i], _cache); if (!value1.Equals(value2)) return false; } return true; } public int GetHashCode(T obj) { return _enableHashCode ? GetHashCode(obj, _columns, _cache) : 0; } private object GetValue(object item, string propertyName, ConcurrentDictionary<string, Func<T, object>> cache) { if (!cache.TryGetValue(propertyName, out Func<T, object> propertyResolver)) { ParameterExpression arg = Expression.Parameter(item.GetType(), "x"); Expression expr = Expression.Property(arg, propertyName); UnaryExpression unaryExpression = Expression.Convert(expr, typeof(object)); propertyResolver = Expression.Lambda<Func<T, object>>(unaryExpression, arg).Compile(); cache.TryAdd(propertyName, propertyResolver); } return propertyResolver((T)item); } private int GetHashCode(T obj, List<string> columns, ConcurrentDictionary<string, Func<T, object>> cache) { unchecked { var hashCode = 17; for (var i = 0; i < columns.Count; i++) { object value = GetValue(obj, columns[i], cache); var tempHashCode = value == null ? 0 : value.GetHashCode(); hashCode = hashCode * 23 + tempHashCode; } return hashCode; } } }
Copie possible de À quoi sert hashCode? Est-ce unique?
Lorsque vous avez débogué via le code, pour chacune des entrées, veuillez partager la valeur de
hashCode
à la fin de chaque itération de boucle for.Quel type et quelle valeur sont renvoyés par votre appel
GetValue ()
dans votre bouclefor
de votre méthodeGetHashCode ()
? Veuillez modifier votre question pour inclure les types (GetType ()
) et le résultatToString ()
de la variablevalue
pour chaque itération de boucle.@Progman Les types et les valeurs sont clairs. Ils ont été définis dans des objets.
@sinanakyazici Quels sont les types et valeurs réels de votre variable
value
dans la bouclefor
? Veuillez modifier votre question pour inclure également les types et les valeurs de chaque itération de boucle. Incluez également le résultat pour toutes les valeurs (hashcode
,tempHashCode
, type et valeur devalue
) non seulement pour l'objett1 < / code> mais aussi pour l'objet
t2
pour comparer le résultat / la sortie pour les différents objets.Vous devez utiliser IEquatable qui a une méthode Compare () afin d'obtenir des valeurs uniques lorsque le hachage donne des doublons. Voir: documents. microsoft.com/en-us/dotnet/api/…
@sinanakyazici Une chance avec ma suggestion?