Philip Pittle
Philip Pittle

Reputation: 12295

IEqualityComparer and Linq Distinct - Hard Code GetHashCode()

I have an array of CustomObject s and a custom IEqualityComparer<CustomObject>. I have hard coded the IEqualityComparer.GetHashCode() method to return a constant 42.

When I run linq's Distinct method on the array, nothing is filtered out. Anyone know why?

Note: I know there are a number of questions on here about this issue, however, the ones I've seen (C# Distinct on IEnumerable<T> with custom IEqualityComparer, Distinct() with lambda?, etc) only say to make sure to implement GetHashCode. None of them explain, why it doesn't work.

Code:

public class CustomObject
{
    public string Name { get; set; }
}

public class CustomObjectEqualityComparer : IEqualityComparer<CustomObject>
{
    public bool Equals(CustomObject x, CustomObject y)
    {
        //Every CustomObject should now be 'equal'!
        return x.GetHashCode() == y.GetHashCode();
    }

    public int GetHashCode(CustomObject obj)
    {
        //Every CustomObject should now be 'equal'!
        return 42;
    }
}

Test:

[TestFixture]
public class TestRunner
{
    private CustomObject[] customObjects = 
    {
        new CustomObject {Name = "Please"},
        new CustomObject {Name = "Help"},
        new CustomObject {Name = "Me"},
        new CustomObject {Name = "Stack"},
        new CustomObject {Name = "Overflow"},
    };

    [Test]
    public void DistinctTest()
    {
        var distinctArray =
            customObjects.Distinct(new CustomObjectEqualityComparer()).ToArray();

        //Since every CustomObject is 'Equal' there should only be
        //1 element in the array.
        Assert.AreEqual(1, distinctArray.Length);
    }
}

This is the output I get from running the test:

 Expected: 5
 But was:  1

If I debug the test, I can see that GetHashCode is being called, so why isn't Distinct filtering out all the 'duplicates'?

Upvotes: 3

Views: 2952

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1500805

When I run linq's Distinct method on the array, nothing is filtered out. Anyone know why?

Yes - Equals is going to return false for any two distinct objects. Within your Equals implementation, you're calling the CustomObject.GetHashCode method (which isn't overridden), not your custom comparer's GetHashCode method. If you expected Equals to call your custom GetHashCode method, you'd need to change it to:

public bool Equals(CustomObject x, CustomObject y)
{
    return GetHashCode(x) == GetHashCode(y);
}

Or given the implementation of GetHashCode(CustomObject), you can just simplify it to:

public bool Equals(CustomObject x, CustomObject y)
{
    return true;
}

Note that your GetHashCode method was being called by Distinct(), but it was then calling your Equals method to check that the objects were really equal... and at that point you were saying that they weren't (barring a massive coincidence).

Upvotes: 8

Related Questions