web-dev-qa-db-fra.com

C # Distinct sur IEnumerable <T> avec IEqualityComparer personnalisé

Voici ce que j'essaie de faire. J'interroge un fichier XML à l'aide de LINQ to XML, ce qui me donne un IEnumerable<T> objet, où T est ma classe "Village", remplie des résultats de cette requête. Certains résultats sont dupliqués, je voudrais donc effectuer un Distinct () sur l'objet IEnumerable, comme ceci:

public IEnumerable<Village> GetAllAlliances()
{
    try
    {
        IEnumerable<Village> alliances =
             from alliance in xmlDoc.Elements("Village")
             where alliance.Element("AllianceName").Value != String.Empty
             orderby alliance.Element("AllianceName").Value
             select new Village
             {
                 AllianceName = alliance.Element("AllianceName").Value
             };

        // TODO: make it work...
        return alliances.Distinct(new AllianceComparer());
    }
    catch (Exception ex)
    {
        throw new Exception("GetAllAlliances", ex);
    }
}

Comme le comparateur par défaut ne fonctionnerait pas pour l'objet Village, j'ai implémenté un comparateur personnalisé, comme on le voit ici dans la classe AllianceComparer:

public class AllianceComparer : IEqualityComparer<Village>
{
    #region IEqualityComparer<Village> Members
    bool IEqualityComparer<Village>.Equals(Village x, Village y)
    {
        // Check whether the compared objects reference the same data.
        if (Object.ReferenceEquals(x, y)) 
            return true;

        // Check whether any of the compared objects is null.
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;

        return x.AllianceName == y.AllianceName;
    }

    int IEqualityComparer<Village>.GetHashCode(Village obj)
    {
        return obj.GetHashCode();
    }
    #endregion
}

La méthode Distinct () ne fonctionne pas, car j'ai exactement le même nombre de résultats avec ou sans elle. Une autre chose, et je ne sais pas si c'est généralement possible, mais je ne peux pas entrer dans AllianceComparer.Equals () pour voir quel pourrait être le problème.
J'ai trouvé des exemples de cela sur Internet, mais je n'arrive pas à faire fonctionner ma mise en œuvre.

J'espère que quelqu'un ici pourrait voir ce qui pourrait mal se passer ici! Merci d'avance!

52
Fueled

Le problème vient de votre GetHashCode. Vous devez le modifier pour renvoyer le code de hachage de AllianceName à la place.

int IEqualityComparer<Village>.GetHashCode(Village obj)
{
    return obj.AllianceName.GetHashCode();
}

Le fait est que si Equals renvoie true, les objets doivent avoir le même code de hachage, ce qui n'est pas le cas pour différents objets Village avec le même AllianceName. Puisque Distinct fonctionne en construisant une table de hachage en interne, vous vous retrouverez avec des objets égaux qui ne seront pas du tout mis en correspondance en raison de codes de hachage différents.

De même, pour comparer deux fichiers, si le hachage de deux fichiers n'est pas le même, vous n'avez pas du tout besoin de vérifier les fichiers eux-mêmes. Ils volonté sois différent. Sinon, vous continuerez de vérifier si elles sont vraiment identiques ou non. C'est exactement ce que la table de hachage que Distinct utilise se comporte.

72
Mehrdad Afshari

return alliances.Select(v => v.AllianceName).Distinct();

Cela retournerait un IEnumerable<string> au lieu de IEnumerable<Village>.

11
superrcat

Ou changez de ligne

return alliances.Distinct(new AllianceComparer());

à

return alliances.Select(v => v.AllianceName).Distinct();
6
Jacob Seleznev