Search code examples
c#listcompare.net-5iequalitycomparer

Correct way to implement IEqualityComparer


I'm currently working on a .net 5.0 application.

I need to implement an IEqualityComparer.

What is the correct way, to implement this interface and prevent NullRefrence Exceptions?

  • My class to compare looks like this:
public class Fruit 
{
   public int Id { get; set; }

   public string Name { get; set; }
}
  • My IEqualityComparer should compare the Ids and looks like this
public class FruitComparer : IEqualityComparer<Fruit>
{
    public bool Equals(Fruit x, Fruit y)
    {
        return x?.Id == y?.Id;
    }

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

The code works fine - but I wonder if that's the way to implement this interface?

What's the correct solution to implement an IEqualityComparer?


Solution

  • That looks largely fine. You're open to a NullReferenceException if someone calls GetHashCode(null), although this is unlikely to happen. You should also make a habit of calling GetHashCode on the members of your type, although for an int that doesn't make any difference.

    A good solution is:

    public int GetHashCode(Fruit obj)
    {
        if (obj is null)
            throw new ArgumentNullException(nameof(obj));
    
        return obj.Id.GetHashCode();
    }
    

    Expanding this to multiple properties is slightly more boilerplate-y, something such as:

    public class FruitComparer : IEqualityComparer<Fruit>
    {
        public bool Equals(Fruit x, Fruit y)
        {
            // Shortcut if they're the same object, and also handles the case
            // where they're both null
            if (ReferenceEquals(x, y))
                return true;
    
            // They're not both null. If either is null, they're not equal
            if (x is null || y is null)
                return false;
    
            // Neither is null. Compare properties.
            return x.First == y.First &&
                x.Second == y.Second; // Etc
        }
    
        public int GetHashCode(Fruit obj)
        {
            if (obj is null)
                throw new ArgumentNullException(nameof(obj));
    
            // Use the HashCode type to combine different properties' hashcodes
            return HashCode.Combine(obj.First, obj.Second);
        }
    }