Creating the GetHashCode method in C#
Asked Answered
E

4

9

What is the best way to create your own GetHashCode method for a class in C#? Suppose I have a simple class (which overrides the Equals method), as follows:

class Test
{
   public string[] names;

   public double[] values;

   public override bool Equals(object obj)
   {
      return (obj is Test) && this.Equals((Test)obj);
   }

   public bool Equals(Test t)
   {
      return names.Equals(t.names) && values.Equals(t.values);
   }
}

Should I use the default code for the GetHashCode method?

public override int GetHashCode()
{
   return base.GetHashCode();
}

Should I base the method on the contents of my class?

public override int GetHashCode()
{
   return names.GetHashCode() + values.GetHashCode() ;
}

Or should I do something else?

Excretion answered 22/7, 2009 at 15:32 Comment(4)
You aren't overriding equals properly here.Janycejanyte
Actually, I think it will lead to stackoverflow.Janycejanyte
No, it won't overflow the stack. However, it won't work, either.Gawen
It already has led him to stackoverflow.Lippizaner
G
13

System.Array does not override GetHashCode or Equals, so they use reference equality. Therefore, you shouldn't call them.

To implement GetHashCode, see this question.

To implement Equals, use the SequenceEqual extension method.

EDIT: On .Net 2.0, you'll have to write your own version of SequenceEqual, like this:

public static bool SequenceEquals<T>(IList<T> first, IList<T> second) {
    if (first == second) return true;
    if (first == null || second == null) return false;

    if (first.Count != second.Count) return false;

    for (int i = 0; i < first.Count; i++)
        if (!first[i].Equals(second[i]))
            return false;

    return true;
}

You could write it to take IEnumerable<T> instead of IList<T>, but it'd be somewhat slower because it wouldn't be able to exit early if the parameters have different sizes.

Gawen answered 22/7, 2009 at 15:36 Comment(1)
Thanks for the excellent and speedy response. Is there an alternative to SequenceEqual that works with .NET framework 2.0?Excretion
L
2

It is really important to make sure you keep the override of .GetHashCode() in step with .Equals().

Basically, you must make sure they consider the same fields so as not to violate the first of the three rules of GetHashCode (from MSDN object.GetHashCode())

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 object do not have to return different values.

In other words, you must make sure that every time .Equals considers two instances equal, they will also have the same .GetHashCode().

As mentioned by someone else here, this question details a good implementation. In case you are interested, I wrote up a few blog articles on investigating hash codes early last year. You can find my ramblings here (the first blog entry I wrote on the subject)

Lambeth answered 22/7, 2009 at 15:46 Comment(0)
T
1

There's a good discussion of the issues here, and the most recent update refers to the BaseObject abstract class provided by SharpArchitecture.

If you want something more ad hoc, I've found that the code that ReSharper generates for Equals() and GetHashCode() is fine.

Taneka answered 22/7, 2009 at 16:29 Comment(0)
C
1

If you use dotnetcore 2.1+, you can use HashCode struct's Combile method to all properties, it's very easily to use and efficiency.

Courtesan answered 15/11, 2019 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.