Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Delegate your equality comparisons

, 14 Apr 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
When using the Linq you often need to distinct your query results. Therefore you need to implement and IEqualityComparer for the more advance scenario’s. For example if you want to distinct on a specific property, or maybe on multiple properties. However this forces you to write lots of infras

When using the Linq you often need to distinct your query results. Therefore you need to implement and IEqualityComparer for the more advance scenario’s. For example if you want to distinct on a specific property, or maybe on multiple properties. However this forces you to write lots of infrastructure code to distinct each type.

You probably would end up with several equality compare classes like this.

public class ProductIdEqualityComparer : IEqualityComparer<Product>
{
    public bool Equals(Product x, Product y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Product obj)
    {
        return obj.Id.GetHashCode();
    }
}

public class ProductPriceEqualityComparer : IEqualityComparer<Product>
{
    public bool Equals(Product x, Product y)
    {
        return x.Price == y.Price;
    }

    public int GetHashCode(Product obj)
    {
        return obj.Price.GetHashCode();
    }
}

public class PersonLastNameEqualityComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return x.LastName == y.LastName;
    }

    public int GetHashCode(Person obj)
    {
        return obj.LastName.GetHashCode();
    }
}

However there is a solution which will save you the work to write all this classes. You will have to write only two classes. One will contain some extension methods, the other has a DelegateEqualityComparer.

public static class CompareExtensions
{
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals, Func<T, int> hashCode)
    {
        return items.Distinct(new DelegateEqualityComparer<T>(equals, hashCode));
    }

    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items, Func<T, T, bool> equals)
    {
        return items.Distinct(new DelegateEqualityComparer<T>(equals, null));
    }
}
public class DelegateEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> _equals;
    private readonly Func<T, int> _hashCode;
    public DelegateEqualityComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
    {
        _equals = equals;
        _hashCode = hashCode;
    }

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

    public int GetHashCode(T obj)
    {
        if (_hashCode != null)
            return _hashCode(obj);
        return obj.GetHashCode();
    }
}

Now you can simply distinct your query by providing a lambda. I tried it on IQueryable, but this doesn’t work. Linq will generate some SQL to do the actual query. We didn’t specified any code that can translate the equality comparer to SQL. If someone figures out how to make it work with IQueryable please let me know.

_products.Distinct((x, y) => x.Id == y.Id, x.Id.GetHashCode());
_products.Distinct((x, y) => x.Price == y.Price, x.Price.GetHashCode());
_persons.Distinct((x, y) => x.LastName == y.LastName, x.LastName.GetHashCode());
_persons.Distinct((x, y) => x.FirstName == y.FirstName, x.FirstName.GetHashCode());
_persons.Distinct((x, y) => x.Address.City == y.Address.City, x.Address.City.GetHashCode());

Share this article if you found it useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

marcofranssen
Software Developer Atos
Netherlands Netherlands
I am a .NET Software Developer at Atos International. Architecture, CQRS, DDD, C#, ASP.NET, MVC3, HTML5, Jquery, WP7, WPF, ncqrs, Node.js
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
SuggestionFormatting PinmvpMika Wendelius14-Apr-12 2:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.1 | Last Updated 14 Apr 2012
Article Copyright 2012 by marcofranssen
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid