Library with Equals and GetHashCode helper methods for .NET
Asked Answered
R

2

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?

Rickettsia answered 27/1, 2012 at 16:8 Comment(0)
M
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.

Melanite answered 27/1, 2012 at 16:23 Comment(5)
+1: tuples and anonymous types are great for implementing GetHashCode(), Equals(), and ToString()Nomenclature
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).Japheth
@LukeH, well since we already have that, and we have this too, that means we can do better than Guava :)Melanite
Really nice approach! The only limitation is that tuples are limited to 8 elements.Rickettsia
@Rickettsia 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; :)Melanite
S
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;
    }
  }
}
Shevlo answered 27/1, 2012 at 16:23 Comment(6)
Your Equals method is exactly the same as the built-in object.Equals(x, y) static method: msdn.microsoft.com/en-us/library/w4hkze5k.aspxJapheth
Equals is not more useful than the inherited standard implementation. It must be possible to state what fields should be considered for equality.Rickettsia
@Rickettsia This is the equivalent to the equals method in Guava. But I'll add this method too.Astronomical
hmm, you're right. The Guava method isn't as useful as it could be.Rickettsia
Put that differently: the Guava method is meant to do something different and simpler. ;)Sender
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.Sabotage

© 2022 - 2024 — McMap. All rights reserved.