11

Google Guava provides nice helpers to implement equals and hashCode like the following example demonstrates:

public int hashCode() {
  return Objects.hashCode(lastName, firstName, gender);
}

Is there a similar library for Microsoft .NET?

deamon
  • 89,107
  • 111
  • 320
  • 448

2 Answers2

21

I don't see why you'd need one. If you want to create a hash-code based on the default GetHashCode for 3 different items, then just use:

Tuple.Create(lastName, firstName, gender).GetHashCode()

That'll boil down to the equivalent of:

int h1 = lastName.GetHashCode();
int h2 = firstName.GetHashCode();
int h3 = gender.GetHashCode();
return (((h1 << 5) + h1) ^ (((h2 << 5) + h2) ^ h3));

Which is pretty reasonable for such a general-purpose combination.

Likewise:

Tuple.Create(lastName, firstName, gender).Equals(Tuple.Create(lastName2, firstName2, gender2))

Would boil down to the equivalent of calling:

return ((lastName == null && lastName2 == null) || (lastName != null && lastName.Equals(lastName2)))
  && ((firstName == null && firstName2 == null) || (firstName != null && firstName.Equals(lastName2)))
  && ((gender == null && gender2 == null) || (gender != null && gender.Equals(lastName2)));

Again, about as good as you could expect.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • 1
    +1: tuples and anonymous types are great for implementing GetHashCode(), Equals(), and ToString() – millimoose Jan 27 '12 at 16:32
  • 1
    Nice idea using the `Tuple` classes as a shortcut. But note that `Tuple.Create(...).Equals(Tuple.Create(...))` isn't equivalent to Guava's `equals` method - that'd just be `object.Equals(x, y)`. – LukeH Jan 27 '12 at 16:32
  • 1
    @LukeH, well since we already have that, and we have this too, that means we can do better than Guava :) – Jon Hanna Jan 27 '12 at 16:35
  • 1
    Really nice approach! The only limitation is that [tuples are limited to 8 elements](http://msdn.microsoft.com/en-us/library/system.tuple.aspx). – deamon Jan 27 '12 at 16:42
  • @deamon `Tuple.Create(m0, m1, m2, m3, m4, m5, m6, Tuple.Create(m7, m8, m9, m10, m11, m12, m13, Tuple.Create(m14, m15, m16, m17, m18...))).GetHashCode()` Though if I really had that many separate (not in a collection) items to consider I'd probably examine the details more seeking to create a custom hashcode that better fitted the likely state of such an object. For a start, many many-field objects can get a good hash-code from `return _id;` :) – Jon Hanna Jan 27 '12 at 16:49
1

AFAIK none. However, writing your own shouldn't be too complex (nb using a variation of the Bernstein hash):

public static class Objects
{
  public static bool Equals<T>(T item1, T item2, Func<T, IEnumerable<object>> selector)
  {
    if (object.ReferenceEquals(item1, item2) return true;
    if (item1 == null || item2 == null) return false;

    using (var iterator1 = selector(item1).GetEnumerator())
    using (var iterator2 = selector(item2).GetEnumerator())
    {
      var moved1 = iterator1.MoveNext();
      var moved2 = iterator2.MoveNext();
      if (moved1 != moved2) return false;
      if (moved1 && moved2)
      {
        if (!Equals(iterator1.Current, iterator2.Current)) return false;
      }
    }
    return true;
  }

  public static bool Equals(object item1, object item2)
  {
    return object.Equals(item1, item2);
  }

  public static int GetHashCode(params object[] objects) 
  {
    unchecked
    {
      int hash = 17;
      foreach (var item in objects)
      {
        hash = hash * 31 + item.GetHashCode();
      }
      return hash;
    }
  }
}
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • Your `Equals` method is exactly the same as the built-in `object.Equals(x, y)` static method: http://msdn.microsoft.com/en-us/library/w4hkze5k.aspx – LukeH Jan 27 '12 at 16:27
  • `Equals` is not more useful than the inherited standard implementation. It must be possible to state what fields should be considered for equality. – deamon Jan 27 '12 at 16:31
  • 1
    @deamon This is the equivalent to the equals method in Guava. But I'll add this method too. – Rich O'Kelly Jan 27 '12 at 16:35
  • hmm, you're right. The Guava method isn't as useful as it could be. – deamon Jan 27 '12 at 16:38
  • 1
    Put that differently: the Guava method is meant to do something different and simpler. ;) – Louis Wasserman Jan 27 '12 at 18:44
  • The comparison of the Enumerators is incorrect. If only one of the Enumerators call to MoveNext returns false, the equal should return false, but this implementation will return true. – CSharpie Apr 17 '15 at 13:17