1

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?

Community
  • 1
  • 1
Evorlor
  • 7,263
  • 17
  • 70
  • 141

1 Answers1

7

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;
 }
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • 1
    Your `Equals` method doesn't check type equality. Because of that, one could argue it is correct only if there are no types that inherit from `Node`. And if `Node` is `public`, that means it would have to be `sealed`. Also, but that's a separate issue, I would probably also implement `IEquatable`, primarily for performance reasons. – Kris Vandermotten Feb 01 '17 at 14:23
  • 1
    @Evorlor: 1. often it's a good practice to test for *reference equality* (instance equals to itself) before starting comparing `myInterface`s (which can be time/resources cosuming) 2. `as` has been specially designed for such comparisons; do not use `GetType` and cast in this case. – Dmitry Bychenko Feb 01 '17 at 14:23
  • @Kris Vandermotten: I agree with you that implmenting `IEquatable` interface is a *good idea*. However, `Equals` compares nodes (of some graph?), not implementations; if a derived class `MyNode` wants to change the policy it should override `Equals` and `GetHashCode` – Dmitry Bychenko Feb 01 '17 at 14:28
  • 1
    If a derived class can override `Equals`, then you can end up in a situation where `a.Equals(b)` is true but `b.Equals(a)` is not, which is weird. The easiest way to avoid that, is of course to make `Node` `sealed`. If that's not possible, checking type equality (as OP did) may help. – Kris Vandermotten Feb 01 '17 at 14:55
  • 1
    @Kris Vandermotten: you are right (I've edited the answer); checking for types seems to be the easiest way out unless the entire `Node` class or at least `GetHashCode` and `Equals` are `sealed`. – Dmitry Bychenko Feb 01 '17 at 15:30