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);

Author: justinmchase

I'm a Software Developer from Minnesota.

Leave a Reply

Discover more from justinmchase

Subscribe now to keep reading and get access to the full archive.

Continue reading