10
votes

C # .NET GETHashCode Fonction Question

Bonjour, j'ai une classe avec 6 propriétés de chaîne. Un objet unique aura des valeurs différentes pour au moins l'un de ces champs

Pour implémenter la fonction gethascode d'IéqualityComparer, je concatéons toutes les 6 propriétés et appelez le gethashcode sur la chaîne résultante.

J'ai eu les doutes suivants:

  1. est-il nécessaire d'appeler le gethashcode sur une valeur unique?
  2. L'opération de concaténation sur les six propriétés rendra la comparaison lente?
  3. Devrais-je utiliser une autre approche?

2 commentaires

Planifiez-vous comparer vos objets quelque part comme les trier dans un tableau ou d'autres? Qui changera sie ou pas vous devez implémenter gethashcode


Bonjour mydogisbox, je l'utilise pour la liste.Contine méthode et passant l'objet de comparateur à celui-ci. J'ai déjà mis en œuvre des égaux et ne connaissez pas la bonne approche pour GetHashCode


4 Réponses :


3
votes

gethashcode () doit renvoyer le même code de hash pour tous les objets qui renvoient true si vous appelez égal () sur ces objets. Cela signifie, par exemple, que vous pouvez retourner zéro en tant que code de hachage indépendamment de ce que sont les valeurs de champ. Mais cela rendrait votre objet très inefficace lorsqu'il serait stocké dans des structures de données telles que des tables de hachage.

La combinaison des chaînes est une option, mais vous pouvez noter que vous pouvez par exemple combiner deux des ficelles du code de hachage (tout en comparant toujours toutes les cordes dans des égaux!).

Vous pouvez également combiner les hachages des six chaînes distinctes, plutôt que de calculer un seul hachage pour une chaîne combinée. Voir par exemple Combinaisons de code de hachage rapides et simples

Je ne suis pas sûr de ne pas être significativement plus rapide que celui de la concaténation de la chaîne.


4 commentaires

Merci ANDERS, je l'utilise uniquement pour la comparaison de la méthode. Si je ne combine que deux chaînes pour le hashcode, les hashcodes sont-elles identiques si les deux valeurs des objets sont identiques? Cela gâcherait-il les comparaisons ou le getHashcode n'a aucun effet sur la comparaison elle-même et n'a que l'impact que la performance


D'autres ont déjà fait ce point, mais j'aimerais y remédier de manière différente, car votre intuition est bloquée. Observez que GetHashCode () renvoie un INT, ce qui ne peut prendre que 2 ^ 32 valeurs différentes. Votre objet, comprenant 6 cordes de longueur arbitraire, peut évidemment prendre un grand nombre de valeurs. Grâce à cet exemple, nous pouvons facilement voir que GetHashCode () ne peut pas être une valeur unique pour toutes les valeurs possibles de votre objet. Il ne doit satisfaire que cette propriété: "Si A.Equals (b), alors A.GethashCode () == b.Gethashcode ()"; et remarquez que "si" ne va pas dans les deux sens.


Les considérations pratiques pour GethashCode () sont-elles «bonnes» et «rapides». Pour le faire "rapide", j'essaierais d'éviter toute allocation de la mémoire et une copie de chaîne; Pour le faire "Bien", c'est un sujet de nuance mais en pratique, il suffit de sauter ensemble les valeurs gethashcode () des sous-objets comme @jon suggère. Je posterai la suggestion de Resharper comme une "réponse" afin que je puisse obtenir le formatage du code.


Merci Corey, je l'obtiens maintenant. Désolé si mes réponses semblaient noobish - car je n'ai pas vraiment obtenu la façon dont le getHashcode fonctionne et est utilisé dans des comparaisons. Je l'ai maintenant.



3
votes

gethashcode n'a pas besoin de renvoyer des valeurs inégales pour des objets "inégaux". Il suffit de renvoyer des valeurs égales pour des objets égaux (il doit également renvoyer la même valeur pour la durée de vie de l'objet).

Cela signifie que:

  1. Si deux objets comparent comme étant égales avec sont égaux , alors leur gethashcode doit renvoyer la même valeur.
  2. Si certaines des 6 propriétés de chaîne ne sont pas strictement en lecture seule, elles ne peuvent pas participer à la mise en œuvre gethashcode .

    Si vous ne pouvez pas satisfaire les deux points en même temps, vous devez réévaluer votre conception car toute autre chose quittera la porte ouverte pour les bugs.

    Enfin, vous pouvez probablement faire gethascode plus rapide en appelant gethascode sur chacune des 6 chaînes, puis en intégrant les 6 résultats dans une seule valeur en utilisant certaines opérations bitwises.


9 commentaires

Salut Jon, aucune de mes propriétés n'est réadonnée. Cependant, ils ont tous des configurateurs privés, ce qui ne peut donc être modifié que du constructeur. Cela affectera-t-il leur utilisation dans gethashcode?


@ganeshran: Ensuite, ils sont en lecture seule sur la durée de vie de l'objet (c'est-à-dire qu'ils pourraient être mis en œuvre avec des champs de support lisonly si vous le souhaitez), ce qui suffit. Vous serez ok.


@Jon Lecture de vos conditions pour la mise en œuvre gethashcode () , je vois qu'il s'agit d'un problème d'exigences contradictoires. En fait, vous n'êtes que partiellement correct. Les exigences réelles pour gethascode () sont les suivantes: 1. Il doit renvoyer les mêmes valeurs pour les objets égaux. 2. Il devrait renvoyer la même valeur pour le même objet alors qu'il n'est pas modifié. 3. Le gethashcode () devrait être rapide. D'accord, qu'il existe d'autres recommandations pour cela. Par exemple, celui-ci: Pour la meilleure performance, une fonction de hachage devrait générer une distribution aléatoire pour toutes les entrées.


Cette phrase répondit pour moi "GetHashCode n'a pas besoin de renvoyer des valeurs inégales pour des objets" inégaux ". Il suffit de renvoyer des valeurs égales pour des objets égaux (il doit également renvoyer la même valeur pour la durée de vie de l'objet)." Je l'ai manqué initialement.


@ganeshran: Notez que est souhaitable de renvoyer des valeurs inégales pour des objets inégaux; Ce n'est tout simplement pas requis (et en effet, il est impossible d'atteindre mathématiquement). Retour 42; est une implémentation "correcte" dans le sens technique, mais cela rendra votre performance souffrir si vous mettez ces objets dans des dictionnaires.


@Jon - oui maintenant je comprends cela après avoir lu les réponses. Ma première idée initiale était que c'était une obligation obligatoire de renvoyer des valeurs inégales pour des objets inégaux. Merci!


@Jon: Si le gethashcode () nous obligerait à utiliser les champs en lecture seule, cela pourrait être impossible pour certaines classes. Par exemple, imaginez un nœud de classe utilisé dans la catégorie LinkedList . Les seuls champs qu'il contient sont les suivants: référence au nœud suivant et à la valeur stockée. Ces deux champs sont mutables (non en lecture seule). La méthode Equals () est définie sur la classe de liste. Il compare simplement tous les éléments stockés de deux listes et renvoie true si chaque paire d'articles est identique. Alors, comment pouvons-nous écrire le gethashcode () pour la liste si nous n'avons pas de champ immuable?


@kekeeperger: Cela dépendrait de la manière dont vous définissez «l'égalité» lorsque nous parlons de listes. Dans ce cas particulier, je voudrais simplement suggérer que pas implémenter iéquatif pour la classe de liste; La notion la plus commune de l'égalité de collecte est déjà mise en œuvre dans Linq comme énumérable.Equensibles .


@Jon: Eh bien, je ne savais pas sur le énumérablement. / Code> qui peut être appliqué parfaitement dans le cas décrit. Mais il n'existe toujours aucun moyen de mettre en œuvre le gethascode pour ma liaison imaginaire. Et d'être honnête, votre idée de l'évasion de Iequatable Mise en œuvre de l'interface n'a pas l'air super pour moi: le énumérable.Equensibles questrequaux n'est pas bien connu pour mes collègues les plus proches en contraste est égal à .



4
votes

Si vos champs de chaîne sont nommés A-F et connus de ne pas être NULL, il s'agit de la proposition de Resharper pour votre gethashcode () xxx


0 commentaires

0
votes

0 commentaires