Domanda

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;
    }

}

Questo si basa su un esempio in "LINQ in Action".Listato 4.16.

Questo stampa Jon Skeet due volte.Perché?Ho anche provato a sovrascrivere il metodo Equals nella classe Autore.Still Distinct non sembra funzionare.Cosa mi manca?

Modificare:Ho aggiunto anche l'overload degli operatori == e !=.Ancora nessun aiuto.

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }
È stato utile?

Soluzione

LINQ distinto non è così intelligente quando si tratta di oggetti personalizzati.

Tutto ciò che fa è guardare la vostra lista e vedere che ha due oggetti diversi (non importa che abbiano gli stessi valori per i campi utente).

Una soluzione è quella di implementare l'interfaccia IEquatable come mostrato qui .

Se si modifica la classe Autore in questo modo dovrebbe funzionare.

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;
    }
}

provare come DotNetFiddle

Altri suggerimenti

I controlli metodo Distinct() riferimento uguaglianza per i tipi di riferimento. Ciò significa che è alla ricerca di letteralmente lo stesso oggetto duplicato, gli oggetti non diverse che contengono gli stessi valori.

C'è un sovraccarico che prende un IEqualityComparer , in modo da poter specificare logica diversa per determinare se un dato oggetto è uguale a un altro.

Se si desidera Autore si comporti normalmente come un oggetto normale (vale a dire solo come riferimento l'uguaglianza), ma ai fini della distinta uguaglianza controllo da valori di nome, utilizzare un IEqualityComparer . Se si desidera che gli oggetti sempre all'autore di essere confrontati in base ai valori del nome, quindi ignorare GetHashCode e Uguale o implementare IEquatable .

I due membri sull'interfaccia IEqualityComparer sono Equals e GetHashCode. La logica per determinare se due oggetti sono Author appare uguali da se la prima e stringhe cognome sono gli stessi.

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();
    }
}

Un'altra soluzione senza implementare IEquatable, Equals e GetHashCode è quello di utilizzare il metodo LINQs GroupBy e per selezionare il primo elemento della 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);
}

C'è un altro modo per ottenere valori distinti dalla lista di utenti definito tipo di dati:

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

Di certo, darà serie distinta di dati

Distinct() esegue il confronto di uguaglianza predefinito sugli oggetti nell'enumerabile.Se non hai eseguito l'override Equals() E GetHashCode(), quindi utilizza l'implementazione predefinita on object, che confronta i riferimenti.

La soluzione semplice è aggiungere a corretto implementazione di Equals() E GetHashCode() a tutte le classi che partecipano all'oggetto grafico che stai confrontando (ad esempio Libro e Autore).

IL IEqualityComparer l'interfaccia è una comodità che ti consente di implementare Equals() E GetHashCode() in una classe separata quando non hai accesso agli interni delle classi che devi confrontare o se stai utilizzando un metodo di confronto diverso.

Non hai Equals sovrascritto (), ma assicuratevi di ignorare anche GetHashCode ()

Le risposte di cui sopra sono sbagliato !!! Distinto come dichiarato su MSDN restituisce il valore predefinito Equatore, che come detto I controlli di proprietà di default se tipo T implementa l'interfaccia System.IEquatable e, in caso affermativo, restituisce un EqualityComparer che utilizza tale implementazione. In caso contrario, restituisce un EqualityComparer che utilizza le sostituzioni di Object.Equals e Object.GetHashCode forniti da T

Il che significa che fino a quando si overide Uguale si sta bene.

Il motivo per cui stai codice non funziona è perché si controlla cognome == cognome.

https://msdn.microsoft.com/library/ bb348436 (v = VS.100) .aspx e https://msdn.microsoft.com/en-us/library/ms224763 (v = VS.100) aspx

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top