Il a été un long temps, mais néanmoins, je pense qu'il est encore nécessaire de donner une réponse correcte à cette question, y compris des explications sur le pourquoi et le comment. La meilleure réponse à ce jour est celui citant le MSDN exhaustivly - n'essayez pas de faire vos propres règles, le MME gars savaient ce qu'ils faisaient.
Mais tout d'abord:
La Directive citée dans la question est mal.
Maintenant, le pourquoi - il y en a deux
D'abord pourquoi:
Si le hashcode est calculée de façon à ce qu'il ne change pas pendant la durée de vie d'un objet, même si l'objet lui-même change, qu'elle allait se briser l'égalité contrat.
Souvenez-vous:
"Si deux objets sont considérées comme égales, la méthode GetHashCode pour chaque objet doit retourner la même valeur. Toutefois, si deux objets ne sont pas considérées comme égales, la GetHashCode méthodes pour les deux objets n'ont pas à renvoyer des valeurs différentes."
La deuxième phrase est souvent interprété à tort comme "La seule règle est, qu'à l'objet de la création, le hashcode de l'égalité des objets doit être égale". Ne sais pas vraiment pourquoi, mais c'est l'essence même de la plupart des réponses ici.
Pensez à deux objets contenant un nom, où le nom est utilisé dans la méthode equals: Même nom -> même chose.
Créer Une Instance: Nom = Joe
Créer Une Instance De B: Nom = Pierre
Hashcode Un et Hashcode B seront plus susceptibles de ne pas être la même.
Ce qui allait arriver maintenant, quand le Nom de l'instance de B est modifié à Joe?
Selon la directive de la question, le hashcode de B ne changerait pas. Le résultat de ce serait:
A. Equals(B) ==> vrai
Mais dans le même temps:
A. GetHashCode() == B. GetHashCode() ==> false.
Mais, justement, ce comportement est interdit explicitement par the equals et hashcode-contrat.
Deuxième pourquoi:
Alors qu'il est - bien sûr - c'est vrai, que les changements dans le hashcode pourrait casser haché listes et d'autres objets à l'aide de la hashcode, l'inverse est vrai aussi. Ne pas changer le hashcode sera dans le pire des cas obtenir haché listes, où tous de tout un tas de différents objets ont le même hashcode et donc être dans le même hachage bin - se produit lorsque les objets sont initialisés avec une valeur standard, par exemple.
Arrive maintenant à le faire
Eh bien, à première vue, il semble y avoir une contradiction - de toute façon, le code de casser.
Mais ni le problème vient de changé ou inchangé hashcode.
La source des problèmes est bien décrite dans la MSDN:
À partir de MSDN de la table de hachage entrée:
Les objets de clé doivent être immuables tant
comme ils sont utilisés comme clés dans le
Table de hachage.
Cela signifie:
Tout objet qui crée un hashvalue devrait changer la hashvalue, lorsque l'objet de modifications, mais il ne doit pas - ne doit absolument pas - de permettre des modifications à lui-même, lorsqu'il est utilisé à l'intérieur d'une table de hachage (ou tout autre de Hachage de l'objet, bien sûr).
D'abord comment
Façon la plus simple serait bien sûr de la conception des objets immuables uniquement pour l'utilisation dans des tables de hachage, qui sera créé en tant que copys de la normale, les objets mutables en cas de besoin.
À l'intérieur de la des objets immuables, c'est obviusly ok pour mettre en cache le hashcode, puisqu'il est immuable.
Deuxième comment
Ou donner l'objet d'un "vous êtes haché maintenant"-drapeau, assurez-vous que toutes les données de l'objet est privé, vérifiez l'indicateur dans toutes les fonctions qui peuvent modifier les objets de données et de lever une exception de données si le changement n'est pas autorisé (c'est à dire le drapeau est réglé).
Maintenant, quand vous mettez l'objet dans toute haché zone, assurez-vous de mettre le drapeau, et - ainsi - unset le drapeau, quand il n'est plus nécessaire.
Pour la facilité d'utilisation, je vous conseille de fixer le drapeau automatiquement à l'intérieur de la "GetHashCode" méthode - de cette façon, il ne peut pas être oublié. Et l'appel explicite d'un "ResetHashFlag" méthode fera en sorte que le programmeur devra penser, si elle est ou n'est pas autorisé à modifier les objets de données.
Ok, ce qui devrait être dit ainsi: Il y a des cas, où il est possible d'avoir des objets avec des données mutable, où le hashcode est néanmoins inchangée, lorsque les objets de données est modifié, sans violer la equals et hashcode-contrat.
Cela nécessite, cependant, que l'égalité méthode n'est pas basée sur les données mutable.
Donc, si j'écris un objet, et de créer une méthode GetHashCode qui ne calculer qu'une fois une valeur et les stocke à l'intérieur de l'objet pour revenir plus tard appels, puis je dois, encore une fois: absolument, créer une méthode Equals, qui va utiliser les valeurs enregistrées pour la comparaison, de sorte que A. Equals(B) ne changera jamais de faux à vrai. Autrement, le contrat serait rompu. Le résultat de ce sera généralement que la méthode Equals n'a aucun sens, c'est pas la référence d'origine est égal, mais ce n'est ni une valeur égale. Parfois, cela peut être l'intention de comportement (c'est à dire des dossiers clients), mais généralement, il ne l'est pas.
Donc, il suffit de faire GetHashCode résultat du changement, les données de l'objet de modifications, et si l'utilisation de l'objet à l'intérieur de hachage à l'aide des listes ou des objets est prévu (ou juste possible), puis faire l'objet soit immuable, soit créer un readonly indicateur à utiliser pour la durée de vie d'un hachage de la liste contenant l'objet.
(En passant: Tout cela n'est pas C# oder .NET spécifiques - c'est dans la nature de tous les hashtable implémentations, ou plus généralement de toute liste indexée, que les données d'identification des objets ne doit jamais changer, tandis que l'objet est dans la liste. Inattendue et imprévisible d'un comportement, si cette règle est enfreinte. Quelque part, il peut y avoir la liste des mises en œuvre, que faire surveiller tous les éléments à l'intérieur de la liste et n'automatique réindexation de la liste - mais la performance de ceux qui vont sûrement être horrible au mieux.)