Question

class Program
{
    static void Main(string[] args)
    {
        List<Book> books = new List<Book> 
        {
            new Book
            {
                Name="C# in Depth",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },
                     new Author 
                    {
                        FirstName = "Jon", LastName="Skeet"
                    },                       
                }
            },
            new Book
            {
                Name="LINQ in Action",
                Authors = new List<Author>
                {
                    new Author 
                    {
                        FirstName = "Fabrice", LastName="Marguerie"
                    },
                     new Author 
                    {
                        FirstName = "Steve", LastName="Eichert"
                    },
                     new Author 
                    {
                        FirstName = "Jim", LastName="Wooley"
                    },
                }
            },
        };


        var temp = books.SelectMany(book => book.Authors).Distinct();
        foreach (var author in temp)
        {
            Console.WriteLine(author.FirstName + " " + author.LastName);
        }

        Console.Read();
    }

}
public class Book
{
    public string Name { get; set; }
    public List<Author> Authors { get; set; }
}
public class Author
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public override bool Equals(object obj)
    {
        return true;
        //if (obj.GetType() != typeof(Author)) return false;
        //else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
    }

}

Ceci est basé sur un exemple dans « LINQ en action ». Liste 4,16.

affiche Jon Skeet deux fois. Pourquoi? J'ai même essayé primordiale méthode Equals Auteur classe. Toujours Distinct ne semble pas fonctionner. Qu'est-ce que je manque?

Edit: J'ai ajouté == et! = Surcharge de l'opérateur aussi. Encore aucune aide.

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }
Était-ce utile?

La solution

LINQ Distinct est pas intelligent quand il s'agit d'objets personnalisés.

Tout ce qu'il fait est de regarder votre liste et de voir qu'il a deux objets différents (il ne se soucie pas qu'ils ont les mêmes valeurs pour les champs membres).

Une solution consiste à implémenter l'interface IEquatable comme le montre .

Si vous modifiez votre classe Auteur comme il devrait fonctionner.

public class Author : IEquatable<Author>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public bool Equals(Author other)
    {
        if (FirstName == other.FirstName && LastName == other.LastName)
            return true;

        return false;
    }

    public override int GetHashCode()
    {
        int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
        int hashLastName = LastName == null ? 0 : LastName.GetHashCode();

        return hashFirstName ^ hashLastName;
    }
}

Essayez comme DotNetFiddle

Autres conseils

Les contrôles de la méthode de référence Distinct() égalité pour les types de référence. Cela signifie qu'il cherche littéralement le même objet, et non dupliquée différents objets qui contiennent les mêmes valeurs.

Il y a un surcharge qui prend un IEqualityComparer , de sorte que vous pouvez spécifier une logique différente pour déterminer si un objet donné est égal à un autre.

Si vous voulez Auteur de se comporter normalement comme un objet normal (à savoir l'égalité référence seulement), mais aux fins de l'égalité de contrôle Distinct par des valeurs de nom, utilisez un IEqualityComparer . Si vous voulez toujours des objets de l'auteur à comparer sur la base des valeurs de nom, puis surchargent GetHashCode et Equals ou mettre en œuvre IEquatable .

Les deux membres sur l'interface IEqualityComparer sont Equals et GetHashCode. Votre logique pour déterminer si deux objets sont égaux Author semble être si les chaînes de nom Prénom et sont les mêmes.

public class AuthorEquals : IEqualityComparer<Author>
{
    public bool Equals(Author left, Author right)
    {
        if((object)left == null && (object)right == null)
        {
            return true;
        }
        if((object)left == null || (object)right == null)
        {
            return false;
        }
        return left.FirstName == right.FirstName && left.LastName == right.LastName;
    }

    public int GetHashCode(Author author)
    {
        return (author.FirstName + author.LastName).GetHashCode();
    }
}

Une autre solution mise en oeuvre sans IEquatable, Equals et GetHashCode est d'utiliser la méthode de LINQs GroupBy et pour sélectionner le premier élément de la IGrouping.

var temp = books.SelectMany(book => book.Authors)
                .GroupBy (y => y.FirstName + y.LastName )
                .Select (y => y.First ());

foreach (var author in temp){
  Console.WriteLine(author.FirstName + " " + author.LastName);
}

Il y a une autre façon d'obtenir des valeurs distinctes de la liste de type de données défini par l'utilisateur:

YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();

Certes, il donnera ensemble distinct de données

Distinct() effectue la comparaison de l'égalité par défaut sur les objets du dénombrable. Si vous n'êtes pas substituée Equals() et GetHashCode() , il utilise l'implémentation par défaut sur object, qui compare les références .

La solution simple consiste à ajouter un correcte mise en œuvre de Equals() et href="http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx" rel="noreferrer"> GetHashCode() à toutes les classes qui participent au graphe d'objet que vous comparez (ie livre et l'auteur).

L'interface IEqualityComparer est une commodité qui vous permet de mettre en œuvre < a href = "http://msdn.microsoft.com/en-us/library/7h9bszxx(VS.80).aspx" rel = "noreferrer"> Equals() et

Vous avez Equals (outrepassée), mais assurez-vous substituez également GetHashCode ()

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