178 votes

Quelle est la différence entre IEqualityComparer<T> et IEquatable<T>?

Je veux comprendre les scénarios IEqualityComparer<T> et IEquatable<T> doit être utilisé. La documentation MSDN pour les deux l'air très similaires.

139voto

Justin Niessner Points 144953

IEqualityComparer<T> est une interface pour un objet qui effectue la comparaison de deux objets de type T.

IEquatable<T> est pour un objet de type T , de sorte qu'il peut se comparer à l'autre.

76voto

stakx Points 29832

Lorsque vous décidez d'utiliser IEquatable<T> ou IEqualityComparer<T>, on pourrait se demander:

Est-il un moyen privilégié de test de deux instances d' T pour l'égalité, ou il y en a plusieurs aussi valides l'une des façons?

  • Si il y a un seul moyen de tester les deux instances de l' T pour l'égalité, ou si l'une de plusieurs méthodes est préférée, IEquatable<T> serait le bon choix: Cette interface est censé être mis en œuvre que par T lui-même, de sorte qu'une instance de T a la connaissance interne de façon à se comparer à une autre instance d' T.

  • D'autre part, s'il y a plusieurs également des méthodes de comparaison de deux Ts pour l'égalité, IEqualityComparer<T> semble plus approprié: Cette interface n'est pas destiné à être mis en œuvre par T lui-même, mais par d'autres "externe" des classes. Par conséquent, lors de l'essai de deux instances de l' T pour l'égalité, parce qu' T n'a pas de connaissance interne de l'égalité, vous aurez à faire un choix explicite d'un IEqualityComparer<T> instance qui effectue le test en fonction de vos exigences spécifiques.

Exemple:

Nous allons tenir compte de ces deux types (qui sont censés avoir une valeur sémantique):

interface IIntPoint : IEquatable<IIntPoint>
{
    int X { get; }
    int Y { get; }
}

interface IDoublePoint  // does not inherit IEquatable<IDoublePoint>; see below.
{
    double X { get; }
    double Y { get; }
}

Pourquoi un seul de ces types héritent IEquatable<>, mais pas dans l'autre?

En théorie, il y a une seule façon logique de la comparaison de deux instances de chaque type: Ils sont égaux si l' X et Y propriétés dans les deux cas, sont égaux. Selon cette pensée, les deux types doivent mettre en œuvre IEquatable<>,, car il ne semble pas probable qu'il existe d'autres moyens efficaces de faire un test d'égalité.

Le problème ici est que la comparaison de nombres à virgule flottante pour l'égalité peut ne pas fonctionner comme prévu, en raison de minutes à des erreurs d'arrondi. Il existe différentes méthodes de comparaison de nombres à virgule flottante pour la quasi-égalité, chacune avec ses avantages et inconvénients, et vous pourriez être en mesure de choisir vous-même la méthode qui convient.

sealed class DoublePointNearEqualityComparerByTolerance : IEqualityComparer<IDoublePoint>
{
    public DoublePointNearEqualityComparerByTolerance(double tolerance) { … }
    …
    public bool Equals(IDoublePoint a, IDoublePoint b)
    {
        return Math.Abs(a.X - b.X) <= tolerance  &&  Math.Abs(a.Y - b.Y) <= tolerance;
    }
    …
}

Notez que la page (ci-dessus) indique explicitement que ce test pour la quasi-égalité a quelques faiblesses. Puisque c'est un IEqualityComparer<T> mise en œuvre, vous pouvez simplement remplacez-la si elle n'est pas assez bon pour vos besoins.

37voto

nawfal Points 13500

Vous avez déjà eu la définition de base de ce qu'ils sont. En bref, si vous implémentez IEquatable<T> classe T, Equals méthode sur un objet de type T vous indique si l'objet lui-même (un cours d'essai pour l'égalité) est égale à une autre instance du même type T. Alors que, IEqualityComparer<T> est pour tester l'égalité de deux instances d' T, généralement en dehors de la portée des instances de T.

Comme pour ce qu'ils sont peut être déroutant au premier abord. À partir de la définition, il devrait être clair que, partant, IEquatable<T> (défini dans la classe T lui-même) doit être la norme de facto pour représenter la singularité de ses objets/instances. HashSet<T>, Dictionary<T, U> (en considérant GetHashCode est remplacé en tant que bien), Contains sur List<T> etc faire usage de cette. La mise en œuvre de IEqualityComparer<T> sur T n'aide pas le ci-dessus mentionné les cas généraux. Par la suite, il n'y a que peu de valeur pour la mise en oeuvre IEquatable<T> sur toute autre catégorie autre que T. Ce:

class MyClass : IEquatable<T>

rarement un sens.

Sur l'autre main

class T : IEquatable<T>
{
    //override ==, !=, GetHashCode and non generic Equals as well

    public bool Equals(T other)
    {
        //....
    }
}

est comment il devrait être fait.

IEqualityComparer<T> peut être utile lorsque vous avez besoin d'une validation personnalisée de l'égalité, mais pas comme une règle générale. Par exemple, dans une classe de Person à un certain point, vous aurez besoin de tester l'égalité de deux personnes sur la base de leur âge. Dans ce cas, vous pouvez le faire:

class Person
{
    public int Age;
}

class AgeEqualityTester : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.Age == y.Age;
    }

    public int GetHashCode(Person obj)
    {
        return Age.GetHashCode;
    }
}

Pour les tester, essayer

var people = new Person[] { new Person { age = 23 } };
Person p = new Person() { age = 23 };

print people.Contains(p); //false;
print people.Contains(p, new AgeEqualityTester()); //true

De même, IEqualityComparer<T> sur T n'a pas de sens.

class Person : IEqualityComparer<Person>

Vrai cela fonctionne, mais n'a pas l'air bon pour les yeux et va à l'encontre de la logique.

Généralement ce que vous avez besoin est - IEquatable<T>. Aussi, idéalement, vous ne pouvez avoir qu'un seul IEquatable<T> alors que plusieurs IEqualityComparer<T> est possible sur la base de différents critères.

L' IEqualityComparer<T> et IEquatable<T> sont exactement analogue à l' Comparer<T> et IComparable<T> qui sont utilisés à des fins de comparaison plutôt que de les assimiler; un bon thread ici où j'ai écrit la même réponse :)

14voto

Chris Shain Points 33569

IEqualityComparer est à utiliser lorsque l'égalité de deux objets en usage externe, mise en œuvre, par exemple, si vous vouliez définir un comparateur pour les deux types que vous n'avez pas la source, ou pour les cas où l'égalité entre les deux choses n'a de sens que dans certains contexte.

IEquatable est pour l'objet lui-même (celui d'être comparé pour l'égalité) à mettre en œuvre.

5voto

Matt Ball Points 165937

On compare les deux Ts. Les autres peuvent se comparer à d'autres Ts. Habituellement, vous aurez seulement besoin d'utiliser un à la fois, pas deux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X