IEqualityComparer facilitado

02/25/2010 23:16:00 By Felipe Pessoto

Quando usamos o Linq temos alguns extension methods muito úteis como Distinct e Except. Porém para fazer uma comparação customizada é necessário criar uma classe que herde de IEqualityComparer<T> e passar uma instancia como parâmetro, o que considero muito sujo, principalmente se cada comparar for de um jeito.

Encontrei uma solução no blog do Brendan Enrick, porém pra mim não funcionou. não sei se fiz algo errado, mas o LINQ sempre chamava primeiro o GetHashCode, que se não fosse igual já retornava false sem nem passar pelo Equals. Alterei para aceitar uma Func que será usada no GetHashCode também, assim só precisamos dessa classe e podemos fazer a chamada da seguinte forma:

List<MyObject> x = myCollection.Except(otherCollection, (x, y) => x.Codigo == y.Codigo, z => z.Codigo).ToList();

Onde "(x, y) => x.Codigo == y.Codigo" é nossa comparação, e  z => z.Codigo o GetHashCode. Assim usamos o Except ou Distinct da mesma maneira que o Where, First, Any, etc

Código:

public static class InterfaceEnumerableExtension
{
     public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,
     IEnumerable<TSource> second, Func<TSource, TSource, bool> comparer, Func<TSource, int> hashFunction)
     {
         return first.Except(second, new LambdaComparer<TSource>(comparer, hashFunction));
     }
 }

public class LambdaComparer<T> : IEqualityComparer<T>
{
     private readonly Func<T, T, bool> lambdaComparer;
     private readonly Func<T, int> lambdaHash;

     public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
     {
         if (lambdaComparer == null)
             throw new ArgumentNullException("lambdaComparer");
         if (lambdaHash == null)
             throw new ArgumentNullException("lambdaHash");

         this.lambdaComparer = lambdaComparer;
         this.lambdaHash = lambdaHash;
     }

     public bool Equals(T x, T y)
     {
         return lambdaComparer(x, y);
     }

     public int GetHashCode(T obj)
     {
         return lambdaHash(obj);
     }
}