Automatic IEqualityComparer There are APIs like the Except extension that require the IEqualityComparer&lt;T&gt; to work. I find it's too much work for such a simple task to implement an interface so I thought why not automate it.



I implemented this interface in a reusable fashion so that I can use it with any value and any number of properties.

internal class AutoEqualityComparer&lt;T&gt; : IEqualityComparer&lt;T&gt;
{
    public AutoEqualityComparer(IEnumerable&lt;Func&lt;T, object&gt;&gt; selectors)
    {
        Selectors = selectors;
    }

    private IEnumerable&lt;Func&lt;T, object&gt;&gt; Selectors { get; }

    public bool Equals(T left, T right)
    {
        return
            !ReferenceEquals(left, null) &amp;&amp;
            !ReferenceEquals(right, null) &amp;&amp;
            Selectors.All(selector =&gt; selector(left).Equals(selector(right)));
    }

    public int GetHashCode(T obj)
    {
        unchecked
        {
            return Selectors
                .Select(selector =&gt; selector(obj).GetHashCode())
                .Aggregate(17, (hashCode, subHashCode) =&gt; hashCode * 31 + subHashCode);
        }
    }
}


I then build a new extension which also can accept any number of selectors to compare:

internal static class Enumerable
{
    public static IEnumerable&lt;T&gt; Except&lt;T&gt;(
        this IEnumerable&lt;T&gt; first, 
        IEnumerable&lt;T&gt; second, 
        params Func&lt;T, object&gt;[] compare)
    {
        var mec = new AutoEqualityComparer&lt;T&gt;(compare);
        return first.Except(second, mec);
    }
}


Example:

Select all properties of an exception that are not in the base exception:

var exceptionProperties =
    typeof(ArgumentException)
    .GetProperties()
    .Except(typeof(Exception).GetProperties(), x =&gt; x.Name);

// result: ParamName is the only property
I think if you created a projection and pass that in the class would be easier to use and more readable for anyone coming after you.  

Instead of the IEnumerable&lt;Func&lt;T, object&gt;&gt; I would change it to be Func&lt;T, K&gt; projection and lose the IEnumerable.  Which would need to make the class now take two generics 

public class AutoEqualityComparer&lt;T, K&gt; : IEqualityComparer&lt;T&gt;
{
    private readonly Func&lt;T, K&gt; _projection;

    public AutoEqualityComparer(Func&lt;T, K&gt; projection)
    {
        _projection = projection;
    }


Since we now have the strong type of class in equals we can use the EqualityComparer class for both the Equals and GetHashCode methods. 

    public virtual bool Equals(T x, T y)
    {
        if (x == null &amp;&amp; y == null)
        {
            return true;
        }
        if (x == null)
        {
            return false;
        }
        if (y == null)
        {
            return false;
        }

        var xData = _projection(x);
        var yData = _projection(y);

        return EqualityComparer&lt;K&gt;.Default.Equals(xData, yData);
    }

    public virtual int GetHashCode(T obj)
    {
        if (obj == null)
        {
            return 0;
        }

        var objData = _projection(obj);

        return EqualityComparer&lt;K&gt;.Default.GetHashCode(objData);
    }


I would create a class to create the AutoEqualityComparer to make it easier to use

public class EqualityProjectionComparer&lt;T&gt;
{
    public static AutoEqualityComparer&lt;T, K&gt; Create&lt;K&gt;(Func&lt;T, K&gt; projection)
    {
        return new AutoEqualityComparer&lt;T, K&gt;(projection);
    }
}


Now with the extension method you can create Tuples or anonymous classes for the IEqualityComparer

Example could be 

var comparer = EqualityProjectionComparer&lt;ArgumentException&gt;.Create(arg =&gt; new
{
    arg.ParamName,
    arg.Message
});


Now to me this is more clear on what we are comparing and anonymous type compare the properties to see if they are equal and not reference.