Implementing Value Object's GetHashCode

We already discussed implementing a Value Object's Equals here and here.

/GetHashCode.png

Now it is time to look at GetHashCode.

When Should You Override GetHashCode?

Each time you override a class's Equals method, the compiler will warn you when you didn't override the GetHashCode method. But why? Where is GetHashCode used?

The answer to that is pretty simple. When you insert a key-value pair in a dictionary/hashtable, .NET uses the GetHashCode of the key to generate an index for the internal array uses in a hashtable (which Dictionary<K, V> also uses). That same GetHashCode is also used to retrieve the value with that (same) key.

Rule #1: Equals means GetHashCode equals

This means that if two key values are equal then the GetHashCode should also be equal. Otherwise, the hashtable will not be able to retrieve its value.

Rule #2: Hashtable keys should be immutable

If you use a certain instance as a key in a hashtable, and then you change (mutate) that instance, the hashtable will not be able to retrieve that key-pair again! So make sure you only use immutable types as a key for a dictionary. Domain-Driven Design Value Objects are ideal for that!

Implementing GetHashCode

Implementing GetHashCode used to be pretty hard to implement manually because you need to take care of a bunch of things. First of all, there is rule #1. And rule #2. A good implementation also returns integer values from the full range of int, not just 1,2,3,... because that results in an inefficient hashtable.

Today writing GetHashCode is easy, thanks to the new HashCode class available in .NET Core. For example:

public override int GetHashCode()
{
  var hash = new HashCode();
  hash.Add(this.Price);
  hash.Add(this.When);
  return hash.ToHashCode();
}

Do take care that you add all properties used in the Equals method (rule #1).

If you're using the U2U.ValueObjectComparers package, life is even easier:

public override int GetHashCode()
  => ValueObjectComparer<MyValueObject>.Instance.GetHashCode(this);

Implementation

The full implementation can be found in my repo.

Just like in implementing Equals I have used "Just Once" reflection to generate a hasher method that internally uses the HashCode class. Then the GetHashCode method simply calls that hasher.

public override int GetHashCode()
  => ValueObjectComparer<YourTypeHere>.Instance.GetHashCode(this);

The GenerateHasher dynamically generates this kind of code:

var hash = new HashCode();
hash.Add(this.Price);
hash.Add(this.When);
return hash.ToHashCode();

With Expression this looks like this:

ParameterExpression obj = Expression.Parameter(typeof(T), "obj");
ParameterExpression hashCode = Expression.Variable(hashCodeType, "hashCode");
BlockExpression block = Expression.Block(
  type: typeof(int),
  variables: new ParameterExpression[] { hashCode },
  expressions: new Expression[]
  {
    Expression.Assign(hashCode, Expression.New(hashCodeType)),
    Expression.Block(GenerateAddToHashCodeExpressions()),
    Expression.Call(hashCode, hashCodeMethod)
  });

The GenerateAddToHashCodeExpressions nested method takes care of calling the Add method for each property:

Expression[] GenerateAddToHashCodeExpressions()
{
  List<Expression> adders = new List<Expression>();
  foreach (PropertyInfo propInfo in typeof(T)
    .GetProperties(BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public))
  {
    if (propInfo.IsDefined(typeof(IgnoreAttribute)))
    {
      continue;
    }
    MethodInfo boundAddMethod = addMethod.MakeGenericMethod(propInfo.PropertyType);
    adders.Add(Expression.Call(hashCode, boundAddMethod, Expression.Property(obj, propInfo)));
  }
  return adders.ToArray();
}

I then wrap the whole thing in a Lambda expression and Compile it:

Func<T, int> hasher = Expression.Lambda<Func<T, int>>(block, obj).Compile();
return hasher;