Je veux comprendre les scénarios où IEqualityComparer<T>
et IEquatable<T>
doivent être utilisés. La documentation MSDN pour les deux semble très similaire.
151
Je veux comprendre les scénarios où IEqualityComparer<T>
et IEquatable<T>
doivent être utilisés. La documentation MSDN pour les deux semble très similaire.
EqualityComparer<T>
au lieu d'implémenter l'interface "carEqualityComparer<T>
teste l'égalité à l'aide deIEquatable<T>
T
implémentationIEquatable<T>
. Une collectionList<T>
aurait-elle une sorte de bogue subtil autrement?Réponses:
IEqualityComparer<T>
est une interface pour un objet qui effectue la comparaison sur deux objets du typeT
.IEquatable<T>
est pour un objet de typeT
afin qu'il puisse se comparer à un autre du même type.la source
IEqualityComparer<T>
est une interface pour un objet (qui est généralement une classe légère différente deT
) qui fournit des fonctions de comparaison qui fonctionnent surT
Au moment de décider d'utiliser
IEquatable<T>
ouIEqualityComparer<T>
, on pourrait se demander:S'il n'y a qu'une seule façon de tester deux instances de
T
pour l'égalité, ou si l'une des méthodes est préférée, alors ceIEquatable<T>
serait le bon choix: cette interface est censée être implémentée uniquement parT
elle-même, de sorte qu'une instance deT
a une connaissance interne de comment se comparer à une autre instance deT
.D'un autre côté, s'il existe plusieurs méthodes également raisonnables pour comparer deux
T
s pour l'égalité,IEqualityComparer<T>
cela semblerait plus approprié: Cette interface n'est pas destinée à être implémentée parT
elle-même, mais par d'autres classes «externes». Par conséquent, lorsque vous testez deux instances deT
pour l'égalité, parce queT
vous n'avez aucune compréhension interne de l'égalité, vous devrez faire un choix explicite d'uneIEqualityComparer<T>
instance qui effectue le test en fonction de vos besoins spécifiques.Exemple:
Considérons ces deux types (qui sont supposés avoir une sémantique de valeur ):
Pourquoi un seul de ces types hériterait-il
IEquatable<>
, mais pas l'autre?En théorie, il n'existe qu'une seule manière raisonnable de comparer deux instances de l'un ou l'autre type: elles sont égales si les propriétés
X
etY
dans les deux instances sont égales. Selon cette réflexion, les deux types devraient être implémentésIEquatable<>
, car il ne semble pas probable qu'il existe d'autres moyens significatifs de faire un test d'égalité.Le problème ici est que la comparaison des nombres à virgule flottante pour l'égalité peut ne pas fonctionner comme prévu, en raison d'erreurs d'arrondi infimes . Il existe différentes méthodes de comparaison des nombres à virgule flottante pour la quasi-égalité , chacune avec des avantages et des compromis spécifiques, et vous voudrez peut-être être en mesure de choisir vous-même la méthode appropriée.
Notez que la page à laquelle j'ai lié (ci-dessus) indique explicitement que ce test de quasi-égalité présente quelques faiblesses. Puisqu'il s'agit d'une
IEqualityComparer<T>
implémentation, vous pouvez simplement l'échanger si ce n'est pas assez bon pour vos besoins.la source
IEqualityComparer<T>
implémentation légitime doit implémenter une relation d'équivalence, ce qui implique que dans tous les cas où deux objets se comparent égaux à un tiers, ils doivent se comparer égaux l'un à l'autre. Toute classe qui implémenteIEquatable<T>
ouIEqualityComparer<T>
d'une manière contraire à ce qui précède est rompue.IEqualityComparer<String>
qui considère "bonjour" comme égal à la fois "Hello" et "hElLo" doit considérer "Hello" et "hElLo" comme étant égaux l'un à l'autre, mais pour la plupart des méthodes de comparaison, ce ne serait pas un problème.GetHashCode
devrait vous permettre de déterminer rapidement si deux valeurs diffèrent. Les règles sont à peu près les suivantes: (1)GetHashCode
doit toujours produire le même code de hachage pour la même valeur. (2)GetHashCode
doit être rapide (plus rapide queEquals
). (3)GetHashCode
n'a pas besoin d'être précis (pas aussi précis queEquals
). Cela signifie qu'il peut produire le même code de hachage pour différentes valeurs. Plus vous pouvez le rendre précis, mieux c'est, mais il est probablement plus important de le garder rapide.Vous avez déjà la définition de base de ce qu'ils sont . En bref, si vous implémentez
IEquatable<T>
sur classeT
, laEquals
méthode sur un objet de typeT
vous indique si l'objet lui-même (celui qui est testé pour l'égalité) est égal à une autre instance du même typeT
. Considérant que,IEqualityComparer<T>
sert à tester l'égalité de deux instances deT
, généralement en dehors de la portée des instances deT
.Quant à savoir à quoi ils servent peut être déroutant au début. D'après la définition, il devrait être clair que par conséquent
IEquatable<T>
(défini dans la classeT
elle - même) devrait être la norme de facto pour représenter l'unicité de ses objets / instances.HashSet<T>
,Dictionary<T, U>
(la considérationGetHashCode
est également remplacée),Contains
surList<T>
etc. La miseIEqualityComparer<T>
en œuvre surT
n'aide pas les cas généraux mentionnés ci-dessus. Par la suite, il y a peu de valeur pour l'implémentationIEquatable<T>
sur une autre classe queT
. Ce:fait rarement sens.
D'autre part
c'est comment cela devrait être fait.
IEqualityComparer<T>
peut être utile lorsque vous avez besoin d'une validation personnalisée de l'égalité, mais pas en règle générale. Par exemple, dans une classe dePerson
à un moment donné, vous devrez peut-être tester l'égalité de deux personnes en fonction de leur âge. Dans ce cas, vous pouvez faire:Pour les tester, essayez
De même
IEqualityComparer<T>
, celaT
n'a pas de sens.C'est vrai que cela fonctionne, mais cela ne semble pas bon aux yeux et va à l'encontre de la logique.
Ce dont vous avez généralement besoin, c'est
IEquatable<T>
. Idéalement aussi, vous ne pouvez en avoir qu'unIEquatable<T>
alors que plusieursIEqualityComparer<T>
sont possibles en fonction de différents critères.Les
IEqualityComparer<T>
etIEquatable<T>
sont exactement analogues àComparer<T>
etIComparable<T>
qui sont utilisés à des fins de comparaison plutôt que d'assimilation; un bon fil ici où j'ai écrit la même réponse :)la source
public int GetHashCode(Person obj)
devrait revenirobj.GetHashCode()
obj.Age.GetHashCode
. va éditer.person.GetHashCode
nulle part .... pourquoi voudriez-vous remplacer cela? - Nous remplaçons parce que tout l'intérêtIEqualityComparer
est d'avoir une implémentation de comparaison différente selon nos règles - les règles que nous connaissons vraiment bien.Age
propriété, donc j'appelleAge.GetHashCode
. L'âge est de typeint
, mais quel que soit le type, c'est le contrat de code de hachage dans .NETdifferent objects can have equal hash but equal objects cant ever have different hashes
. C'est un contrat auquel nous pouvons croire aveuglément. Bien sûr, nos comparateurs personnalisés doivent également adhérer à cette règle. Si jamais appelersomeObject.GetHashCode
casse les choses, alors c'est le problème avec les implémenteurs de type desomeObject
, ce n'est pas notre problème.IEqualityComparer est à utiliser lorsque l'égalité de deux objets est implémentée en externe, par exemple si vous souhaitez définir un comparateur pour deux types dont vous n'avez pas la source, ou pour les cas où l'égalité entre deux choses n'a de sens que dans un contexte limité.
IEquatable est pour l'objet lui-même (celui qui est comparé pour l'égalité) à implémenter.
la source
On compare deux
T
art. L'autre peut se comparer à d'autresT
art. Habituellement, vous n'aurez besoin d'en utiliser qu'un à la fois, pas les deux.la source