Equality

This is something that I’m surprised isn’t included in the framework out of the box. When using the Distinct Query operator, one of the overloads takes an IEqualityComparer<T> instance. There is friction in creating a separate IEqualityComparer<T> implementation for every object you want to compare and in some cases, Equality means something different depending on context so you don’t necessarily want to implement IEqualiyComparer<T> directly on your T (and/or you aren’t able to do so because it is a class from someone’s library).

Whatever your reason, here is a generic implementation of IEqualityComparer that works similar to my DelegateCommand. You create an instance of it on the spot (or cache an instance) passing in lambdas that represent your equality logic.

public class Equality<T> : IEqualityComparer<T>
{
    private readonly Func<T, int> _hashFunc;
    private readonly Func<T, T, bool> _equalsFunc;

    public Equality(Func<T,int>hashFunc)
    {
        _hashFunc = hashFunc;
        _equalsFunc = (x, y) => x.GetHashCode() == y.GetHashCode();
    }

    public Equality(Func<T,int>hashFunc, Func<T,T,bool>equalsFunc )
    {
        _hashFunc = hashFunc;
        _equalsFunc = equalsFunc;
    }

    public bool Equals(T x, T y)
    {
        //can't compare null
        if (typeof(T).IsClass)
        {
            if (x == null || y == null)
                return false;
        }
        return _equalsFunc(x, y);
    }

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

The first constructor overload takes just the hash function and specifies that the hashcode is your identifier (great for entities with an Int as their id). The second constructor takes a hash function and an equality function. Using Equality<T> is as simple as:

var manufacturers =
     Catalogs.Select(c => c.Product.ManuFacturer).Distinct(new Equality<ManuFacturer>(i => i.Id));

Hope it’s useful to you!

Published Thursday, March 18, 2010 4:42 PM by Mike Brown

Leave a Comment

(required) 
(required) 
(optional)
(required)