Question

J'ai lu environ 10 questions différentes sur quand et comment passer outre GetHashCode mais il y a encore quelque chose que je ne comprends pas tout à fait. La plupart des implémentations de sont basées sur Equals les codes de hachage des champs de l'objet, mais il a été cité que la valeur ne doit jamais changer == pendant toute la durée de l'objet. Comment ça marche si les champs qu'il est basé sur des mutable? Aussi si je ne veux dictionnaire etc pour les recherches fondées sur l'égalité de référence pas mon substituée ValueEquals?

Je suis avant tout primordial .Equals pour la facilité de tests unitaires mon code de sérialisation que je suppose sérialisation et désérialisation (au format XML dans mon cas) tue l'égalité de référence donc je veux vous assurer au moins il est juste en valeur l'égalité . Est-ce une mauvaise pratique pour remplacer dans ce cas a.Equals(b)? En fait, dans la plupart du code exécution je veux l'égalité de référence et je l'utilise toujours et je suis a.GetHashCode() pas que remplaçant. Devrais-je créer une nouvelle méthode ou quelque chose au lieu == b.GetHashCode() de passer outre a? Je l'habitude de supposer que le cadre utilise toujours et non .Equals() de comparer les choses IEquatable et je pensais qu'il était sûr de passer outre, car il me <=> semblait comme son but était car si vous voulez avoir une 2ème définition de l'égalité qui est différent de l'opérateur <=>. De la lecture de plusieurs questions mais il semble que ce n'est pas le cas.

EDIT:

Il semble que mes intentions ne sont pas claires, ce que je veux dire est que 99% du temps je veux simplement ancienne égalité de référence, le comportement par défaut, pas de surprises. Pour les cas très rares je veux avoir la valeur d'égalité, et je veux demander explicitement l'égalité de valeur en utilisant au lieu de <=> <=>.

Quand je fais le compilateur recommande-je remplacer ainsi <=>, et voilà comment cette question a été soulevée. Il semblait que il y a des objectifs contredisant pour <=> lorsqu'il est appliqué à des objets mutables, ceux être:

  1. Si alors <=> doit <=> <=>.
  2. La valeur ne doit jamais de changer <=> pour la durée de vie <=>.

Ceux-ci semblent contredire naturellement quand un objet mutable, parce que si l'état de l'objet change, nous nous attendons à la valeur de changer <=>, ce qui signifie que devrait changer pour <=> correspondre au changement de <=>, mais ne devrait pas changer <=>.

Pourquoi il semble y avoir cette contradiction? ces recommandations ne sont pas destinées à appliquer aux objets mutables? Probablement supposé, mais peut-être utile de mentionner que je fais référence à des classes non struct.

Résolution:

Je marque JaredPar comme acceptée, mais surtout pour l'interaction des commentaires. En résumé de ce que j'ai appris est que la seule façon d'atteindre tous les objectifs et d'éviter un comportement bizarre possible dans les cas de pointe est seulement override et <=> en fonction des champs <=> immuables, ou mettre en œuvre <=>. Ce genre de semble diminuer l'utilité de passer outre pour les types de <=> référence, à partir de ce que je l'ai vu la plupart des types de référence ont généralement pas de champs immuables à moins qu'ils sont stockés dans une base de données relationnelle pour les identifier avec leurs clés primaires.

Était-ce utile?

La solution

Comment ça marche si les champs qu'il est basé sur des mutable?

Il ne constitue pas en ce sens que le code de hachage changera à mesure que l'objet change. C'est un problème pour toutes les raisons énumérées dans les articles que vous lisez. Malheureusement, c'est le type de problème qui ne montrent généralement dans les cas d'angle. Alors les développeurs ont tendance à sortir avec le mauvais comportement.

De plus si je ne veux dictionnaire etc pour les recherches fondées sur l'égalité de référence ne mes Equals surchargées?

Tant que vous implémentez une interface comme cela ne devrait pas IEquatable<T> être un problème. La plupart des implémentations dictionnaire choisiront un comparateur d'égalité d'une manière qui utilisera plus Object.ReferenceEquals IEqualityComparer<T>. Même sans EqualityComparer<T>.Default, la plupart par défaut d'appeler Object.Equals () qui sera ensuite aller dans votre mise en œuvre.

En gros, dans la plupart du code exécution je veux l'égalité de référence et je l'utilise toujours == et je ne suis pas que remplaçant.

Si vous attendez de vos objets à se comporter avec l'égalité de valeur que vous devez remplacer == et! = Pour appliquer la valeur de l'égalité pour toutes les comparaisons. Les utilisateurs peuvent toujours utiliser Object.ReferenceEquals si elles veulent réellement l'égalité de référence.

Je l'habitude de supposer que le cadre utilise toujours == et non Equals pour comparer les choses

Ce que les utilisations de la BCL a un peu changé au fil du temps. Maintenant, la plupart des cas qui utilisent l'égalité prendront un exemple et utiliser <=> pour l'égalité. Dans les cas où l'on n'est spécifié qu'ils utiliseront pour trouver un <=>. ce sera par défaut au pire des cas, d'appeler Object.Equals

Autres conseils

Si vous avez un objet mutable, il n'y a pas beaucoup d'intérêt à redéfinissant la méthode GetHashCode, comme vous ne pouvez pas utiliser vraiment. Il est utilisé par exemple par les collections Dictionary et de placer HashSet chaque élément dans un seau. Si vous modifiez l'objet alors qu'il est utilisé comme une clé de la collection, le code de hachage ne correspond plus le seau que l'objet est, de sorte que la collection ne trouve pas correctement et vous pouvez jamais l'objet.

Si vous voulez que la recherche ne pas utiliser la méthode ou GetHashCode de la classe Equals, vous pouvez toujours fournir votre propre implémentation de la place à utiliser IEqualityComparer lorsque vous créez le <=>.

La méthode est destinée à <=> l'égalité de valeur, il est donc pas tort de mettre en œuvre cette façon.

Wow, c'est en fait plusieurs questions en une :-). Donc, l'un après l'autre:

  

il a été cité que la valeur de GetHashCode ne devrait jamais changer au cours de la durée de vie de l'objet. Comment ça marche si les champs qu'il est basé sur des mutable?

Ce conseil commun est conçu pour le cas où vous souhaitez utiliser votre objet comme une clé dans un Hashtable / dictionnaire etc. Hashtables exigent habituellement le hachage de ne pas changer, car ils l'utilisent pour décider comment stocker et récupérer la clé. Si les changements de hachage, Hashtable ne sera probablement pas plus trouver votre objet.

Pour citer la documentation de Java de Carte Interface:

Remarque: le plus grand soin doit être exercé que si les objets mutables sont utilisés comme clés de carte. Le comportement d'une carte n'est pas spécifié si la valeur d'un objet est modifié d'une manière qui affecte égale des comparaisons alors que l'objet est une clé dans la carte.

En général, il est une mauvaise idée d'utiliser any type d'objet mutable comme une clé dans une table de hachage: Il n'y a même pas clairement ce qui devrait se produire si un changement clé après qu'il a été ajouté à la table de hachage . la table de hachage doit retourner l'objet stocké par l'ancienne clé, ou via la nouvelle clé, ou par les deux?

Alors le vrai conseil est: utilisez uniquement des objets immuables comme clés, et assurez-vous que leur hashcode ne change jamais non plus (ce qui est généralement automatique si l'objet est immuable)

.
  

De plus si je ne veux dictionnaire etc pour les recherches fondées sur l'égalité de référence ne mes Equals surchargées?

Eh bien, trouver une implémentation dictionnaire qui fonctionne comme ça. Mais les dictionnaires bibliothèque standard utilisent la hashcode & Equals, et il n'y a aucun moyen de changer cela.

  

Je suis avant tout primordial Equals pour la facilité de tests unitaires mon code de sérialisation que je suppose sérialisation et désérialisation (au format XML dans mon cas) tue l'égalité de référence donc je veux vous assurer au moins il est correct par l'égalité de valeur. Est-ce une mauvaise pratique de passer outre Equals dans ce cas?

Non, je trouverais cela parfaitement acceptable. Cependant, vous ne devriez pas utiliser ces objets comme les clés dans un dictionnaire / Hashtable, car ils sont mutables. Voir ci-dessus.

Le thème sous-jacent est ici comment mieux identifier de manière unique les objets. Vous mentionnez sérialisation / désérialisation qui est important parce que l'intégrité référentielle est perdue dans ce processus.

La réponse courte est que les objets doivent être identifiés de manière unique par le plus petit ensemble de champs immuables qui peuvent être utilisés pour le faire. Ce sont les champs que vous devez utiliser lors overrideing GetHashCode et Equals.

Pour le tester est tout à fait raisonnable de définir ce que les affirmations dont vous avez besoin, en général ceux-ci ne sont pas définies sur le type lui-même, mais plutôt comme des méthodes d'utilité dans la suite de tests. Peut-être un TestSuite.AssertEquals (MaClasse, MaClasse)?

Notez que GetHashCode et Equals doivent travailler ensemble. GetHashCode doit retourner la même valeur pour deux objets si elles sont égales. Equals doit retourner vrai si et seulement si deux objets ont le même code de hachage. (Notez qu'il est possible que deux objets ne peut pas être égale, mais peut retourner le même code de hachage). Il y a beaucoup de page Web qui s'attaquer de front cette question, juste google loin.

Je ne sais pas C #, être un noob par rapport à lui, mais en Java, si vous remplacez equals (), vous devez remplacer également hashCode () pour maintenir le contrat entre eux (et vice-versa) .. . Et java a aussi la même prise 22; obligez, fondamentalement, vous utilisez des champs immuables ... Mais cela est un problème que pour les classes qui sont utilisés comme un hachage clé et Java implémentations alternatives pour a toutes les collections à base de hachage ... qui peut-être pas aussi vite, mais ils effecitely vous permettent d'utiliser un objet mutable comme une clé ... il est juste (habituellement) fronça les sourcils comme une « mauvaise conception ».

Et je me sens l'envie de souligner que ce problème fondamental est hors du temps ... Il a été autour depuis Adam était un garçon.

Je travaille sur le code Fortran qui est plus âgé que moi (je suis 36) qui casse quand un nom d'utilisateur est changé (comme quand une fille se marie, ou divorcé ;-) ... est ainsi l'ingénierie, la solution adoptée était: la GetHashCode « méthode », se souvient l'hashCode calculé précédemment, recalcule le hashCode (soit un marqueur IsDirty virtuel) et si les KeyFields ont changé retourne null. Cela provoque le cache pour supprimer l'utilisateur « sale » (en appelant une autre GetPreviousHashCode), puis le cache retourne null, ce qui provoque l'utilisateur de relire à partir de la base de données. Une astuce intéressante et utile; même si je ne dis moi-même; -)

Je vais Compromis mutabilité (seulement souhaitable dans les cas d'angle) O (1) l'accès (souhaitable dans tous les cas). Bienvenue à l'ingénierie; la terre du compromis éclairé.

Vive. Keith.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top