Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Library with Equals and GetHashCode helper methods for .NET

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?

like image 968
deamon Avatar asked Jan 27 '12 16:01

deamon


People also ask

How does GetHashCode work in C#?

GetHashCode method of the base class uses reflection to compute the hash code based on the values of the type's fields. In other words, value types whose fields have equal values have equal hash codes.

Why do we need to override hashcode and equals Method C#?

It is because the framework requires that two objects that are the same must have the same hashcode. If you override the equals method to do a special comparison of two objects and the two objects are considered the same by the method, then the hash code of the two objects must also be the same.

Why should we override equals method in C#?

For a value type, you should always override Equals, because tests for equality that rely on reflection offer poor performance. You can also override the default implementation of Equals for reference types to test for value equality instead of reference equality and to define the precise meaning of value equality.

Should override equals C#?

With value types, you should always override the == operator. Like the Equals method, the default implementation of the == operator uses reflection and is slow. Use the same logic as the Equals method, and you'll get much better performance when you're doing equality comparisons on value types.


2 Answers

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.

like image 152
Jon Hanna Avatar answered Nov 15 '22 17:11

Jon Hanna


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;
    }
  }
}
like image 28
Rich O'Kelly Avatar answered Nov 15 '22 16:11

Rich O'Kelly