linq lambda anonymous-types iequalitycomparer

linq - IEqualityComparer para tipo anónimo



lambda anonymous-types (3)

tengo esto

var n = ItemList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList(); n.AddRange(OtherList.Select(s => new { s.Vchr, s.Id, s.Ctr, s.Vendor, s.Description, s.Invoice }).ToList(););

Me gustaría hacer esto si estuviera permitido

n = n.Distinct((x, y) => x.Vchr == y.Vchr)).ToList();

Intenté utilizar el LambdaComparer genérico, pero como estoy utilizando tipos anónimos no hay ningún tipo de asociado con él.

"Ayudame Obi Wan Kenobi, eres mi única esperanza"


El truco es crear un comparador que solo funcione en tipos inferidos. Por ejemplo:

public class Comparer<T> : IComparer<T> { private Func<T,T,int> _func; public Comparer(Func<T,T,int> func) { _func = func; } public int Compare(T x, T y ) { return _func(x,y); } } public static class Comparer { public static Comparer<T> Create<T>(Func<T,T,int> func){ return new Comparer<T>(func); } public static Comparer<T> CreateComparerForElements<T>(this IEnumerable<T> enumerable, Func<T,T,int> func) { return new Comparer<T>(func); } }

Ahora puedo hacer lo siguiente ... solución hacky:

var comp = n.CreateComparerForElements((x, y) => x.Vchr == y.Vchr);


La mayoría de las veces, cuando se compara (por igualdad o clasificación), le interesa elegir las claves para comparar, no el método de igualdad o comparación en sí (esta es la idea detrás de la API de clasificación de listas de Python).

Aquí hay un comparador de igualdad clave de ejemplo.


Observo que la respuesta de JaredPar no responde del todo la pregunta, ya que los métodos establecidos como Distinct y Except requieren un IEqualityComparer<T> no es un IComparer<T> . Lo siguiente asume que un IEtabletable tendrá un GetHashCode adecuado, y ciertamente tiene un método Equals adecuado.

public class GeneralComparer<T, TEquatable> : IEqualityComparer<T> { private readonly Func<T, IEquatable<TEquatable>> equatableSelector; public GeneralComparer(Func<T, IEquatable<TEquatable>> equatableSelector) { this.equatableSelector = equatableSelector; } public bool Equals(T x, T y) { return equatableSelector.Invoke(x).Equals(equatableSelector.Invoke(y)); } public int GetHashCode(T x) { return equatableSelector(x).GetHashCode(); } } public static class GeneralComparer { public static GeneralComparer<T, TEquatable> Create<T, TEquatable>(Func<T, TEquatable> equatableSelector) { return new GeneralComparer<T, TEquatable>(equatableSelector); } }

Donde se usa la misma inferencia de un truco de clase estático como en la respuesta de JaredPar.

Para ser más general, podría proporcionar dos Func : a Func<T, T, bool> para verificar la igualdad y Func<T, T, int> para seleccionar un código hash.