52 votes

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

Voici ce que je suis en train de faire. Je suis interrogation d'un fichier XML à l'aide de LINQ to XML, ce qui me donne un IEnumerable<T>, où T est mon "Village" de la classe, rempli avec les résultats de cette requête. Certains résultats sont dupliqués, donc je voudrais effectuer un Distinct() sur l'objet IEnumerable, comme suit:

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 serait pas travailler pour le Village d'objet, j'ai mis en place un programme personnalisé, comme on le voit ici dans le AllianceComparer classe:

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, 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 possible, mais je ne peut pas en AllianceComparer.Equals() pour voir ce qui pourrait être le problème.
J'ai trouvé des exemples sur Internet, mais je n'arrive pas à faire mon travail de mise en œuvre.

Heureusement, quelqu'un ici pourrait voir ce qui pourrait être mal ici! Merci à l'avance!

72voto

Mehrdad Afshari Points 204872

Le problème est avec votre GetHashCode. Vous devriez les modifier, il renvoie le code de hachage de l' AllianceName à la place.

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

La chose est, si Equals retours true, les objets doivent avoir le même code de hachage qui n'est pas le cas pour les différents Village objets avec le même AllianceName. Depuis Distinct travaux par la construction d'une table de hachage en interne, vous vous retrouverez avec les objets égaux à ne pas être appariés à tous en raison de différents codes de hachage.

De même, pour comparer deux fichiers, si le hash de deux fichiers ne sont pas les mêmes, vous n'avez pas besoin de vérifier les fichiers eux-mêmes. Ils vont être différents. Sinon, vous continuerez à vous de vérifier pour voir si elles sont vraiment la même chose ou pas. C'est exactement ce que la table de hachage Distinct utilise se comporte.

11voto

superrcat Points 109

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

Qui retourne un IEnumerable<string> au lieu de IEnumerable<Village>.

6voto

Jacob Seleznev Points 4761

Ou de modifier la ligne

return alliances.Distinct(new AllianceComparer());

pour

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

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