Pergunta

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

}

Isso é baseado em um exemplo em "Linq em ação". Listagem 4.16.

Isso imprime Jon Skeet duas vezes. Por quê? Eu até tentei substituir o método Equals na classe do autor. Ainda distinto não parece funcionar. o que estou perdendo?

EDIT: Eu também adicionei == e! = Sobrecarga do operador. Ainda não há ajuda.

 public static bool operator ==(Author a, Author b)
    {
        return true;
    }
    public static bool operator !=(Author a, Author b)
    {
        return false;
    }
Foi útil?

Solução

O Linq Distinct não é tão inteligente quando se trata de objetos personalizados.

Tudo o que faz é olhar para a sua lista e ver que ela possui dois objetos diferentes (não se importa que eles tenham os mesmos valores para os campos de membros).

Uma solução alternativa é implementar a interface iEquatável, como mostrado aqui.

Se você modificar sua classe de autor, como deve funcionar.

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

Experimente como dotnetfiddle

Outras dicas

o Distinct() Método verifica a igualdade de referência para tipos de referência. Isso significa que está procurando literalmente o mesmo objeto duplicado, não objetos diferentes que contêm os mesmos valores.

Há um sobrecarga que leva um IequityCompare, para que você possa especificar uma lógica diferente para determinar se um determinado objeto é igual a outro.

Se você deseja que o autor normalmente se comporte como um objeto normal (ou seja, referência à igualdade), mas para fins de igualdade de verificação distinta por valores de nome, use um IequityCompare. Se você sempre deseja que os objetos do autor sejam comparados com base nos valores do nome, então Substituir Gethashcode e é igual, ou implementar iequatable.

Os dois membros no IEqualityComparer interface são Equals e GetHashCode. Sua lógica para determinar se dois Author Os objetos são iguais, parece ser se as seqüências de nome do primeiro e do sobrenome forem iguais.

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

Outra solução sem implementar IEquatable, Equals e GetHashCode é usar o LINQS GroupBy método e para selecionar o primeiro item no 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);
}

Há mais uma maneira de obter valores distintos da lista do tipo de dados definido pelo usuário:

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

Certamente, ele dará um conjunto distinto de dados

Distinct() Executa a comparação de igualdade padrão em objetos no enumerável. Se você não substituiu Equals() e GetHashCode(), então ele usa a implementação padrão em object, que compara referências.

A solução simples é adicionar um correto implementação de Equals() e GetHashCode() Para todas as classes que participam do gráfico de objetos que você está comparando (ou seja, livro e autor).

o IEqualityComparer A interface é uma conveniência que permite que você implemente Equals() e GetHashCode() Em uma aula separada quando você não tem acesso aos internos das classes que precisa comparar ou se estiver usando um método diferente de comparação.

Você substitui Equals (), mas certifique -se de substituir o gethashcode ()

As respostas acima estão erradas !!! Distinto, conforme declarado no MSDN, retorna o equador padrão que indicado A propriedade padrão verifica se o tipo T implementa a interface do sistema. Caso contrário, ele retorna um EqualityComparer que usa as substituições de objeto.

O que significa que, desde que você exagere, você está bem.

O motivo pelo qual seu código não está funcionando é porque você verifica o primeiro nome == Nome.

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top