Question

Je veux comprendre les scénarios où IEqualityComparer<T> et IEquatable<T> doit être utilisé. La documentation MSDN pour les deux est très similaire.

Était-ce utile?

La solution

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

IEquatable<T> est un objet de type T afin qu'il puisse se comparer à un autre.

Autres conseils

Au moment de décider si vous souhaitez utiliser IEquatable<T> ou IEqualityComparer<T> , on peut se demander:

Y at-il un meilleur moyen de tester deux instances de T pour l'égalité, ou y at-il plusieurs façons tout aussi valables?

  • S'il n'y a qu'une seule façon de tester deux instances de T pour l'égalité, ou si l'une de plusieurs méthodes est préférable, alors 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 une connaissance interne de la façon de se situer par rapport à une autre instance de T.

  • Par contre, s'il existe plusieurs méthodes tout aussi raisonnable de comparer deux Ts pour l'égalité, IEqualityComparer<T> semble plus approprié: Cette interface ne vise pas à être mis en œuvre par T lui-même, mais par d'autres classes « externes » . Par conséquent, lors du test de deux instances de T pour l'égalité, parce T n'a pas connaissance interne de l'égalité, vous devrez faire un choix explicite d'une instance de IEqualityComparer<T> qui effectue le test en fonction de vos besoins spécifiques.

Exemple:

Considérons ces deux types (qui sont censés avoir sémantique de valeur ):

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ériter IEquatable<>, mais pas l'autre?

En théorie, il n'y a qu'une seule façon raisonnable de comparer deux instances de chaque type: Ils sont égaux si les propriétés de X et Y dans les deux cas sont égaux. Selon cette pensée, les deux types devraient mettre en œuvre IEquatable<>, 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 comparer les nombres à virgule flottante pour l'égalité pourrait ne pas fonctionner comme prévu, en raison à des erreurs d'arrondi minute . Il existe différentes méthodes de comparaison des nombres à virgule flottante pour quasi-égalité , chacun avec des avantages spécifiques et des compromis, et vous voudrez peut-être en mesure de vous choisir la méthode appropriée.

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 I lié à (ci-dessus) indique explicitement que ce test pour quasi-égalité a quelques faiblesses. Comme il est une implémentation IEqualityComparer<T>, vous pouvez simplement échangez si ce n'est pas assez bon pour vos besoins.

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

ce qu'ils sont pour peut être déroutant au premier abord. De la définition, il doit être clair que par conséquent IEquatable<T> (défini dans la classe elle-même T) devrait être la norme de facto pour représenter le caractère unique de ses objets / instances. HashSet<T>, Dictionary<T, U> (considérant GetHashCode est surchargée aussi bien), Contains sur List<T> etc faire usage de cela. La mise en œuvre IEqualityComparer<T> sur T ne permet pas les cas généraux mentionnés ci-dessus. Par la suite, il y a peu de valeur pour la mise en œuvre IEquatable<T> sur toute autre catégorie autre que T. Ceci:

class MyClass : IEquatable<T>

fait rarement sens.

D'autre part

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

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

est de savoir comment il faut le faire.

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 de Person à un moment donné, vous pourriez avoir besoin de tester l'égalité de deux personnes en fonction de leur âge. Dans ce cas, vous pouvez 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 obj.Age.GetHashCode;
    }
}

Pour les tester, essayez

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>

True cela fonctionne, mais il ne semble pas bon à la logique des yeux et des défaites.

En général, ce que vous avez besoin est IEquatable<T>. Aussi, vous pouvez idéalement avoir un seul IEquatable<T> alors que plusieurs IEqualityComparer<T> est possible en fonction de différents critères.

Le IEqualityComparer<T> et IEquatable<T> sont exactement analogue à Comparer<T> et IComparable<T> qui sont utilisés à des fins de comparaison au lieu d'assimiler; un bon fil où j'ai écrit la même réponse:)

IEqualityComparer est destiné à être utilisé lorsque l'égalité de deux objets est mis en oeuvre à l'extérieur, par exemple, si vous voulez définir un comparateur pour 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 un contexte limité.

IEquatable est pour l'objet lui-même (l'une étant comparée à l'égalité) à mettre en œuvre.

On compare deux Ts. L'autre peut se comparer à d'autres Ts. Habituellement, vous aurez seulement besoin d'utiliser un à au moment, pas les deux.

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