mrb398
mrb398

Reputation: 1317

IEqualityComparer using list of string as comparer

I'm attempting to setup an IEqualityComparer that uses a list of string as the comparing property.

When using Except and Intersect in the 2 lines of code below, all records are seen as 'new' and none are recognized as 'old'.

List<ExclusionRecordLite> newRecords = currentRecords.Except(historicalRecords, new ExclusionRecordLiteComparer()).ToList();
List<ExclusionRecordLite> oldRecords = currentRecords.Intersect(historicalRecords, new ExclusionRecordLiteComparer()).ToList();

This is my IEqualityComparer class (Words is a List)

public class RecordComparer : IEqualityComparer<Record>
{
    public bool Equals(Record x, Record y)
    {
        if (object.ReferenceEquals(x, y))
            return true;

        if (x == null || y == null)
            return false;

        return x.Words.SequenceEqual(y.Words);
    }

    public int GetHashCode(Record obj)
    {
        return new { obj.Words }.GetHashCode();
    }
}

Upvotes: 4

Views: 4570

Answers (2)

Tim Schmelter
Tim Schmelter

Reputation: 460158

Your GetHashCode is incorrect. Use one like this:

public override int GetHashCode()
{
    if(Words == null) return 0;
    unchecked
    {
        int hash = 19;
        foreach (var word in Words)
        {
            hash = hash * 31 + (word == null ? 0 : word.GetHashCode());
        }
        return hash;
    }
}

To answer why a collection does not override GetHashCode but uses object.GetHashCode which returns a unique value: Why does C# not implement GetHashCode for Collections?

Upvotes: 7

Sean
Sean

Reputation: 62492

Assuming you're storing Words in a List then calling GetHashCode on it won't give you back a hash of the items in it, instead it'll give you back the hash value from Object.GetHashCode.

You need to implement your own hash function that enumerates over the words and generates a hash value.

Upvotes: 0

Related Questions