Comment comparer des types complexes avec Enumerable.Distinct et LINQ ?

Comment doit-on s’y prendre pour recouper, en éléments distincts, une liste composée d’objets complexes? À un moment donné ou à un autre, nous avons tous eu à faire cela. Heureusement, c’est là qu’intervient la méthode Enumerable.Distinct().

Par définition, la méthode Distinct() permet de retourner une liste composée des éléments distincts de la collection d’origine.

Naturellement, il est simple d’utiliser Distinct avec une liste composée de types primitifs comme int, string, long et double, par exemple. La comparaison est déjà prévue dans le framework .NET.

Cependant, la situation est entièrement différente lorsqu’il est temps d’utiliser un type complexe avec Distinct. Comment doit s’y prendre pour deviner la clé pour comparer les différents éléments de la liste?

L’option la plus évidente est d’implémenter l’interface IEqualityComparer. Ce n’est pas par hasard que je le mentionne, car c’est justement une des signatures permises par Distinct. Vous pouvez créer une classe pour implémenter une comparaison, selon vos besoins, de votre type complexe.

Cela signifie que vous devez spécifier votre propre définition qu’égalité entre deux instances de ce type. Pour .NET, la définition d’égalité se définit par les méthodes suivantes:

  1. la valeur retournée par GetHashCode() doit être égale pour les deux objets comparés
  2. En cas de valeur différente au point précédent, une comparaison sera effectuée avec la méthode Equals() des deux instances.

Distinct et IEqualityComparer en exemple

Considérez les deux extraits de code suivant

et l’application console suivante

Êtes-vous en mesure de prédire le résultat de l’exécution? Dans la console, la chaîne de texte « Montréal » sera retournée à l’écran, car il s’agit de la valeur qui est comparée par la classe User.Comparer.

Certains pourraient argumenter que de faire un override des méthodes GetHashCode et Equals directement revient exactement au même. Là où je ne suis pas en accord c’est sur le principe que d’implémenter IEqualityComparer a le mérite d’exprimer clairement une intention.

Dans ce cas-ci, c’est de définir que deux utilisateurs sont recoupés en fonction de leur emplacement de connexion. L’élégance de la chose est qu’il n’y a rien qui vous empêche de développer plusieurs comparateurs implémentant IEqualityComparer selon le contexte où vous vous trouvez.

Sources

Advertisements

2 avis sur « Comment comparer des types complexes avec Enumerable.Distinct et LINQ ? »

  1. Christophe dit :

    J’aime bien aussi l’idée de l’interface IEqualityComparer pour que ça soit explicite… Par contre me suis simplifié la vie pour ne pas avoir à écrire un comparateur par type en m’inspirant de ça:
    http://www.blackwasp.co.uk/LambdaEqualityComparer.aspx

Laisser un commentaire

Entrer les renseignements ci-dessous ou cliquer sur une icône pour ouvrir une session :

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l’aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment ce contenu :