c# linq distinct anonymous-types equality

c# - LINQ Select Distinct con tipos anónimos



anonymous-types equality (7)

Ejecuté una pequeña prueba y descubrí que si las propiedades son tipos de valores, parece funcionar bien. Si no son tipos de valor, entonces el tipo necesita proporcionar sus propias implementaciones Equal y GetHashCode para que funcione. Cuerdas, creo, funcionarían.

Entonces tengo una colección de objetos. El tipo exacto no es importante. De ella quiero extraer todos los pares únicos de un par de propiedades particulares, así:

myObjectCollection.Select(item=>new { Alpha = item.propOne, Bravo = item.propTwo } ).Distinct();

Entonces mi pregunta es: Distintará en este caso usar el objeto predeterminado igual (que será inútil para mí, ya que cada objeto es nuevo) o se le puede decir que haga un igual diferente (en este caso, valores iguales de Alfa y Bravo) => instancias iguales)? ¿Hay alguna manera de lograr ese resultado, si esto no lo hace?


Es interesante que funcione en C # pero no en VB

Devuelve las 26 letras:

var MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"; MyBet.ToCharArray() .Select(x => new {lower = x.ToString().ToLower(), upper = x.ToString().ToUpper()}) .Distinct() .Dump();

Devuelve 52 ...

Dim MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ" MyBet.ToCharArray() _ .Select(Function(x) New With {.lower = x.ToString.ToLower(), .upper = x.ToString.ToUpper()}) _ .Distinct() _ .Dump()


Hola, tengo el mismo problema y encontré una solución. Debe implementar la interfaz IEquatable o simplemente anular los métodos (Equals & GetHashCode). Pero este no es el truco, el truco está en el Método GetHashCode. No debe devolver el código hash del objeto de su clase, pero debe devolver el hash de la propiedad que desea comparar así.

public override bool Equals(object obj) { Person p = obj as Person; if ( obj == null ) return false; if ( object.ReferenceEquals( p , this ) ) return true; if ( p.Age == this.Age && p.Name == this.Name && p.IsEgyptian == this.IsEgyptian ) return true; return false; //return base.Equals( obj ); } public override int GetHashCode() { return Name.GetHashCode(); }

Como ves obtuve una clase llamada Persona obtuve 3 propiedades (Nombre, Edad, IsEgyptian "Porque soy") En el GetHashCode, devolví el hash de la propiedad Name y no el objeto Person.

Pruébalo y funcionará ISA. Gracias, Modather Sadik


Lea el excelente post de K. Scott Allen aquí:

E igual para todos ... Tipos anónimos

La respuesta corta (y cito):

Resulta que el compilador de C # anula Equals y GetHashCode para los tipos anónimos. La implementación de los dos métodos reemplazados utiliza todas las propiedades públicas del tipo para calcular el código hash de un objeto y probar la igualdad. Si dos objetos del mismo tipo anónimo tienen todos los mismos valores para sus propiedades, los objetos son iguales.

Por lo tanto, es totalmente seguro utilizar el método Distinct () en una consulta que devuelve tipos anónimos.


Puede crear su propio método de Extensión Distinct que tome la expresión lambda. Aquí hay un ejemplo

Crea una clase que se deriva de la interfaz IEqualityComparer

public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T, int> _hashCode; public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode) { _equals= equals; _hashCode = hashCode; } public bool Equals(T x, T y) { return _equals(x, y); } public int GetHashCode(T obj) { if(_hashCode!=null) return _hashCode(obj); return obj.GetHashCode(); } }

Luego crea tu método de Extensión Distinct

public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals, Func<T,int> hashCode) { return items.Distinct(new DelegateComparer<T>(equals, hashCode)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals) { return items.Distinct(new DelegateComparer<T>(equals,null)); } }

y puedes usar este método para encontrar elementos distintos

var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName}) .Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList();


Si Alpha y Bravo heredan de una clase común, usted podrá dictar la verificación de igualdad en la clase padre implementando IEquatable<T> .

Por ejemplo:

public class CommonClass : IEquatable<CommonClass> { // needed for Distinct() public override int GetHashCode() { return base.GetHashCode(); } public bool Equals(CommonClass other) { if (other == null) return false; return [equality test]; } }


public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T, int> _hashCode; public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode) { _equals= equals; _hashCode = hashCode; } public bool Equals(T x, T y) { return _equals(x, y); } public int GetHashCode(T obj) { if(_hashCode!=null) return _hashCode(obj); return obj.GetHashCode(); } } public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals, Func<T,int> hashCode) { return items.Distinct(new DelegateComparer<T>(equals, hashCode)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals) { return items.Distinct(new DelegateComparer<T>(equals,null)); } } var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName}) .Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList();

Perdón por el formateo desordenado anterior