Expression Equality Comparer

I was just encountering an issue where I needed to get the distinct elements of two collections but not necessarily distinct instances. When trying to resolve this issue I found the convenient Linq method “Distinct”. By default it will return to you distinct instances but if you want to evaulate equality based on some other qualification then you’re stuck with creating a custom IEqualityComparer<T>. There may be something in the framework already that solves this problem but I couldn’t find it. So I created a really simple Expression based equality comparer and a corresponding enumerable extension method.

public static class Enumerable
{
    public static IEnumerable<T> Distinct<T>(
        this IEnumerable<T> items, 
        Expression<Func<T, T, bool>> equalityComparer)
    {
        ExpressionEqualityComparer<T> comparer = 
            new ExpressionEqualityComparer<T>(equalityComparer);
        return items.Distinct(comparer);
    }
}

public class ExpressionEqualityComparer<T> : EqualityComparer<T>
{
    private Func<T, T, bool> equals;
    public ExpressionEqualityComparer(
        Expression<Func<T, T, bool>> equals)
    {
        this.equals = equals.Compile();
    }

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

    public override int GetHashCode(T obj)
    {
        return base.GetHashCode();
    }
}

This allows you to call Distinct with an expression as a parameter which is used to evaluate equality rather than requiring you to create a custom comparer object every time. It calls its own GetHashCode() instead of the objects in order to ensure that different instances will still evaluate through the equality comparer. Here is an example of the usage.

Example[] c1 = new Example[] { 
    new Example { Id = 1, Name = "one" }, 
    new Example { Id = 2, Name = "two" } };
Example[] c2 = new Example[] { 
    new Example { Id = 2, Name = "two" }, 
    new Example { Id = 3, Name = "three" } };

var c3 = c1.Concat(c2).Distinct((e1, e2) => e1.Name == e2.Name);
Advertisements

Drop a brain bomb

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s