Qu’est-ce qui doit être remplacé dans une structure pour garantir que l’égalité fonctionne correctement?

Comme le titre l’indique: dois-je remplacer l’opérateur == ? .Equals() méthode .Equals() ? Quelque chose me manque?

Un exemple de msdn

 public struct Complex { double re, im; public override bool Equals(Object obj) { return obj is Complex && this == (Complex)obj; } public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } public static bool operator ==(Complex x, Complex y) { return x.re == y.re && x.im == y.im; } public static bool operator !=(Complex x, Complex y) { return !(x == y); } } 

Vous devez également implémenter IEquatable . Voici un extrait des lignes direcsortingces de conception du cadre:

DO implémenter IEquatable sur les types de valeur. La méthode Object.Equals sur les types de valeur provoque la boxe et son implémentation par défaut n’est pas très efficace car elle utilise la reflection. IEquatable.Equals peut offrir de bien meilleures performances et peut être implémenté de manière à ne pas provoquer de boxe.

 public struct Int32 : IEquatable { public bool Equals(Int32 other){ ... } } 

Suivez les mêmes instructions que pour écraser Object.Equals lors de l’implémentation d’IEquatable.Equals. Reportez-vous à la section 8.7.1 pour des directives détaillées sur la substitution d’Object.Equals

Malheureusement, je n’ai pas assez de réputation pour commenter d’autres entrées. Donc, je publie des améliorations possibles à la meilleure solution ici.

Corrigez-moi, si je me trompe, mais la mise en œuvre mentionnée ci-dessus

 public struct Complex { double re, im; public override bool Equals(Object obj) { return obj is Complex && this == (Complex)obj; } public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } public static bool operator ==(Complex x, Complex y) { return x.re == y.re && x.im == y.im; } public static bool operator !=(Complex x, Complex y) { return !(x == y); } } 

A un défaut majeur. Je fais référence à

  public override int GetHashCode() { return re.GetHashCode() ^ im.GetHashCode(); } 

XORing est symésortingque, donc Complex (2,1) et Complex (1,2) donneraient le même hashCode.

Nous devrions probablement faire quelque chose de plus comme:

  public override int GetHashCode() { return re.GetHashCode() * 17 ^ im.GetHashCode(); } 

La plupart du temps, vous pouvez éviter d’implémenter Equals et GetHashcode dans les structures, car le compilateur a implémenté automatiquement les types Value utilisant un contenu binary et une reflection pour les membres de référence.

Jetez un coup d’oeil à ce post: Quel est le meilleur pour Struct / Classes de magasin de données?

Donc, pour plus de facilité d’utilisation, vous pouvez toujours implémenter == et! =.

Mais la plupart du temps, vous pouvez éviter d’implémenter Equals et GetHashcode.
Un cas où vous devez implémenter Equals et GetHashCode concerne un champ que vous ne souhaitez pas prendre en compte.
Par exemple, un champ qui varie au fil du temps, comme Age d’une personne ou instantSpeed ​​d’une voiture (l’identité de l’object ne devrait pas changer si vous voulez la retrouver dans le dictionnaire au même endroit).

Cordialement, meilleur code

La différence fondamentale entre les deux est que l’opérateur == est statique, c’est-à-dire que la méthode appropriée à invoquer est déterminée au moment de la compilation, tandis que la méthode Equals est invoquée sur une instance.
Définir les deux est probablement la meilleure chose à faire, même si cela est moins important dans le cas des structures, car les structures ne peuvent pas être étendues (une structure ne peut pas hériter d’une autre).

Juste pour la complétude je conseillerais aussi de surcharger la méthode Equals :

 public bool Equals(Complex other) { return other.re == re && other.im == im; } 

c’est une réelle amélioration car il n’y a pas de boxe dans l’argument d’entrée de la méthode Equals(Object obj)

Quelques bonnes pratiques d’utilisation des types de valeur:

  • les rendre immuables
  • remplacer Equals (celui qui prend un object comme argument);
  • surcharge Equals pour prendre une autre instance du même type de valeur (par exemple * Equals (Complex other));
  • surcharger les opérateurs == et! =;
  • remplacer GetHashCode

Cela vient de ce post: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/