GetHashCode() the easy way

CODING ·
c# GetHashCode VS2017 VS2019 .Net

Remembering the most appropriate way to calculate a hashcode was always difficult. But not anymore

tl;dr

Let Visual Studio generate your overrides for Equals() and GetHashCode() so you don’t need to remember the best practices.

Don’t roll your own GetHashCode() algorithm or even rely on StackOverflow, use the .net framework to work it out for you..

HashCode.Combine(Long, Lat, Altitude);

Background

When trying to check the equality of reference objects in c# we simply cannot apply the ‘==’ operator, as this will only compare memory locations and not data.

To get around this every object implements both the Equals() and GetHashCode() methods. According to MSDN The purpose of GetHashCode() is:

The GetHashCode method provides this hash code for algorithms that need quick checks of object equality.

The main points to take into consideration when calculating the hash code are:

A hash function must have the following properties:

  • If two objects compare as equal, the GetHashCode() method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode() methods for the two objects do not have to return different values.

  • The GetHashCode() method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object’s System.Object.Equals method. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.

  • For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered. An implication is that small modifications to object state should result in large modifications to the resulting hash code for best hash table performance.

  • Hash functions should be inexpensive to compute.

  • The GetHashCode() method should not throw exceptions. MSDN

Of these the most important to note are points 3 and 4: It should generate an even distribution and should be inexpensive.

In the good ol’ days

After searching around you would usually find an implementation (which I did recently) along the lines of the following:

public override int GetHashCode()
{
  unchecked
  {
    int hash = 17;

    hash = hash * 23 + Lat.GetHashCode();
    hash = hash * 23 + Long.GetHashCode();
    hash = hash * 23 + Altitude.GetHashCode();
    return hash;
  }
}

I’m not going to claim I know how the maths works out, but I’m told it just does and that it satisifies the requirements mentioned above.

I’ve never been happy with this, as I am unable to prove the even distribution etc requirements, and am I missing brackets to ensure order of operation???

These days

Well, today I stumbled across this little Gem inside VS2017 (also VS2019).

Starting with:

public class Location
{
  public int Long { get; set; }
  public int Lat { get; set; }
  public int Altitude { get; set; }
}

Place the cursor on the Class definition and open the Quick Actions menu ‘ctrl + .’, then select “Generate Equals and GetHashCode…”

Quick actions menu

Select which properties you want included in your equality check and voila. you are good to go. As an optional extra you can even choose to implement IEquatable too.

Generate Equals and GetHashCode options

public class Location : IEquatable<Location>
{
  public int Long { get; set; }
  public int Lat { get; set; }
  public int Altitude { get; set; }

  public override bool Equals(object obj)
  {
    return Equals(obj as Location);
  }

  public bool Equals(Location other)
  {
    return other != null &&
            Long == other.Long &&
            Lat == other.Lat &&
            Altitude == other.Altitude;
  }

  public override int GetHashCode()
  {
    return HashCode.Combine(Long, Lat, Altitude);
  }
}

The final point of note is the calculation of the HashCode. No longer do we need to remember how to calculate, or worry about the effiency or the distribution because Microsoft have given us a handy helper

HashCode.Combine(Long, Lat, Altitude);

And thats it, one less thing for me to think about.