Pregunta

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

}

Esto se basa en un ejemplo de "LINQ en acción".Listado 4.16.

Esto imprime a Jon Skeet dos veces.¿Por qué?Incluso intenté anular el método Equals en la clase Autor.Aún así, Distinct no parece funcionar.¿Qué me estoy perdiendo?

Editar:También agregué la sobrecarga del operador == y !=.Todavía no hay ayuda.

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

Solución

LINQ distinto no es tan inteligente cuando se trata de objetos personalizados.

Todo lo que hace es mirar a su lista y ver que tiene dos objetos diferentes (que no le importa que tienen los mismos valores para los campos miembros).

Una solución consiste en implementar la interfaz IEquatable como se muestra aquí .

Si modifica su clase de Autor como lo que debería 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;
    }
}

probar, ya que DotNetFiddle

Otros consejos

el método comprueba Distinct() Referencia igualdad para los tipos de referencia. Esto significa que está buscando, literalmente, el mismo objeto duplicado no diferentes objetos, que contienen los mismos valores.

Hay una sobrecarga que toma un IEqualityComparer , para que pueda especificar la lógica diferente para determinar si un objeto dado es igual a otro.

Si desea Autor comportarse normalmente como un objeto normal (es decir, la igualdad única referencia), pero a los efectos de la igualdad de verificación Distinto por valores de nombres, utilice un IEqualityComparer . Si siempre desea que los objetos autor a ser comparado basan en los valores de nombre, a continuación, reemplazar GetHashCode y Equals o aplicar IEquatable .

Los dos miembros en la interfaz IEqualityComparer son Equals y GetHashCode. Su lógica para determinar si dos objetos son Author parece ser iguales a si la primera y cadenas de nombres Últimos son los mismos.

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

Otra solución sin implementar IEquatable, Equals y GetHashCode es utilizar el método LINQs GroupBy y para seleccionar el primer elemento 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);
}

Hay otra manera de obtener valores distintos de lista de usuario tipo de datos definido:

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

Sin duda, dará conjunto distinto de datos

Distinct() realiza la comparación de igualdad predeterminada en objetos en el enumerable.Si no has anulado Equals() y GetHashCode(), luego usa la implementación predeterminada en object, que compara referencias.

La solución simple es agregar un correcto implementación de Equals() y GetHashCode() a todas las clases que participan en el gráfico de objetos que está comparando (es decir, Libro y Autor).

El IEqualityComparer La interfaz es una comodidad que le permite implementar Equals() y GetHashCode() en una clase separada cuando no tiene acceso a las partes internas de las clases que necesita comparar, o si está utilizando un método de comparación diferente.

Que haya anulado Iguales (), pero asegúrese de que también reemplazar GetHashCode ()

Las respuestas anteriores son incorrectas !!! Distinta como se indica en MSDN devuelve el ecuador por defecto que como se ha dicho Los controles de propiedad por defecto si el tipo T implementa la interfaz System.IEquatable y, si es así, devuelve un EqualityComparer que utiliza esa aplicación. De lo contrario, devuelve un EqualityComparer que utiliza las anulaciones de las Object.equals y Object.GetHashCode proporcionados por T

Lo que significa que todo el tiempo que overide Es igual a que estés bien.

El motivo por el que el código no está funcionando es porque se comprueba apellido == apellido.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top