Search code examples
c#hashcodeequalitygethashcodeiequalitycomparer

How do I override GetHashCode() without any numbers as fields?


All of the resources showing how to override Equals(object) and GetHashCode() use numeric fields to implement the GetHashCode() method:

Implementing the Equals Method
What's the best strategy for Equals and GetHashCode?
Why is it important to override GetHashCode when Equals method is overridden?

However, in my class, I do not have any numeric fields. It is a node in a tree with a reference to its parent, children, and an interface as the data:

public class Node
{
    private IInterface myInterface;
    private Node parent;
    private List<Node> children = new List<Node>();

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        var node = (Node)obj;
        return myInterface == node.myInterface;
    }

    public override int GetHashCode()
    {
        ???
    }
}

What should I set the hashcode with?


Solution

  • According to Equals implementation, two Nodes instances are equal if and only if their myInterface are equal:

    public override bool Equals(object obj)
    {
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
        var node = (Node)obj;
    
        // instances are equal if and only if myInterface's are equal
        return myInterface == node.myInterface;
    }
    

    That's why myInterface is the only source for GetHashCode:

     public override int GetHashCode()
     {
        return null == myInterface ? 0 : myInterface.GetHashCode();
     }
    

    P.S. (Edited, thanks to Kris Vandermotten) Often, it's a good practice to check for ReferenceEquals in the Equals implementation before comparing potentially time/resource consuming myInterfaces:

     public override bool Equals(object obj) {
       // Easy tests: 
       // 1. If "this" and "obj" are in fact just the same reference?
       // 2. Since `Node` (or Equals) is not sealed, the safiest is to check types 
       if (object.ReferenceEquals(this, obj))
         return true;
       else if (null == obj || other.GetType() != GetType()) 
         return false;
    
       // Potentially time/resource cosuming (we don't know IInterface implementation)
       return ((Node) obj).myInterface == myInterface;
     }