Search code examples
c#hashsetiequalitycomparer

C# HashSet not using defined IEqualityComparer<>


I am trying to compare two HashSets of objects by using .SetEquals(). I looked at some guides and saw that I needed to implement IEqualityComparer<> as part of the class in order for it to work properly. However, I have found that .SetEquals() is failing when I use it.

I have verified that the data I am attempting to compare is the same by using Lists and comparing them one element at a time. I am suspecting that I have implemented the IEqualityComparer<> incorrectly and it's using the default Equals() and GetHashCode().

Here's the code I am using:

public class MemberDataRow : IEqualityComparer<MemberDataRow>
{
    public string ID { get; }
    public string FirstName { get; }
    public string MI { get; }
    public string LastName { get; }
    public decimal Premium { get; }
    public string MemberCount { get; }
    public string RateCell { get; }
    public string RateCellDescription { get; }
    public string Month { get; }
    public bool Kickback { get; }
    public decimal PrivateBalance { get; }
    public decimal StateBalance { get; }
    public decimal PrivateAssets { get; }
    public decimal StateAssets { get; }
    public decimal MUG { get; }
    public DateTime Date { get; }
 
    // Constructor Stuff is here. Removed for easier reading

    bool IEqualityComparer<MemberDataRow>.Equals(MemberDataRow? x, MemberDataRow? y)
    {
        if ((x.ID == y.ID) &&
            (x.FirstName == y.FirstName) &&
            (x.MI == y.MI) &&
            (x.LastName == y.LastName) &&
            (x.Premium == y.Premium) &&
            (x.MemberCount == y.MemberCount) &&
            (x.RateCell == y.RateCell) &&
            (x.RateCellDescription == y.RateCellDescription) &&
            (x.Month == y.Month) &&
            (x.Kickback == y.Kickback) &&
            (x.PrivateBalance == y.PrivateBalance) &&
            (x.PrivateAssets == y.PrivateAssets) &&
            (x.StateBalance == y.StateBalance) &&
            (x.StateAssets == y.StateAssets) &&
            (x.MUG == y.MUG) &&
            (x.Date == y.Date))
            return true;
        else
            return false;
    }

    int IEqualityComparer<MemberDataRow>.GetHashCode(MemberDataRow obj)
    {
        // HashCode.Combine() only allows 7 arguments, so we have to chain them together.
        return HashCode.Combine(
            HashCode.Combine(obj.ID, obj.FirstName, obj.MI, obj.LastName, obj.Premium, obj.MemberCount, obj.RateCell),
            HashCode.Combine(obj.RateCellDescription, obj.Month, obj.Kickback, obj.PrivateBalance, obj.PrivateAssets, obj.StateBalance),
            HashCode.Combine(obj.StateAssets, obj.MUG, obj.Date));
        }
    }

Solution

  • I think what you want to do here is implement IEquatable<MemberDataRow>. The interface that you're implementing now is meant to be implemented by a separate "comparer" class that you pass in the constructor of a HashSet object instead.

    See also here.