3

The more I read the more confused I am from blogs, to MSDN, to other stackoverflow questions and responses.

This article: https://msdn.microsoft.com/en-us/library/ms173147%28VS.90%29.aspx States: "The new implementation of Equals should not throw exceptions. It is recommended that any class that overrides Equals also override Object.GetHashCode"

But this article: http://www.aaronstannard.com/overriding-equality-in-dotnet/ States: "An important caveat - you should only override GetHashCode if your objects are immutable."

1) So, do I listen to the first article straight from Microsoft? Or do I listen to the second article who seems to have a much stronger hashcode return than Microsoft.

2) If using the Microsoft example, the example returns the instance members int values using exclusive-OR. Is this something I do with all value types? How come there is an option on the int32 struct to return the hashcode then? When do I return the hashcode vs the value?

3) When do I use the more complex hashcode return (from the second article) vs the more simple from the first (Microsoft) article

4)If the object is immutable and cannot be changed, and two immutable objects of the same type are Equal by value, then why would the HashCode matter?

dugas
  • 12,025
  • 3
  • 45
  • 51
eaglei22
  • 2,589
  • 1
  • 38
  • 53
  • 2
    That's a lot of questions for one post (and most if not all of them already discussed to death on SO). Some of questions you can consider - http://stackoverflow.com/questions/873654/overriding-gethashcode-for-mutable-objects, http://stackoverflow.com/questions/462451/gethashcode-guidelines-in-c-sharp – Alexei Levenkov Feb 10 '16 at 19:41
  • I've answered the first part of your post. Please only ask one question per post. – Jon Skeet Feb 10 '16 at 19:49
  • Your question 4 is equivalent to "Why would a hash code *ever* matter?". For that you need to understand how hash tables work (Wikipedia). – usr Feb 10 '16 at 19:50

2 Answers2

4

1) Both articles are correct. They do not contradict each other. If you override GetHashCode() in a mutable object, you might e.g. place it in a HashSet, change properties of the object therefore changing the hash code, then be unable to find it in the HashSet.

2) XOR is a weak means of combining multiple integer values. For a better approach see Combining Java hashcodes into a "master" hashcode

3) You need to ensure that the hash code you return will minimize hash collisions between objects that represent different values. You need to better describe your domain for a good answer.

4) The hash code is used for things like dictionaries and hash sets. If you have a Dictionary<MyType, int> you want to avoid two instances of MyType hashing to the same value and therefore being considered the same key if they are in fact unequal.

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • Thanks Eric. You bring up a good point in #1, something the Microsoft documentation doesn't touch on. – eaglei22 Feb 10 '16 at 19:59
  • There are a ton of in-depth discussions on SO already. Check out the Linked and Related stuff to the right of this page to get more depth on the subject. – Eric J. Feb 10 '16 at 20:00
  • @user1794106: From the `object.GetHashCode` documentation: " If you do choose to override GetHashCode for a mutable reference type, your documentation should make it clear that users of your type should not modify object values while the object is stored in a hash table." – Jon Skeet Feb 10 '16 at 20:56
4

To my mind, you should always override GetHashCode if you override Equals - otherwise you're violating the contracts of those methods.

However, for mutable types, client code needs to be aware that if it does mutate a value used as a key in a Dictionary or an entry in a HashSet, in a way that affects equality (and thus probably the hash code), they may well end up not being able to find it again. That's specified in the Dictionary<,> documentation, for example:

As long as an object is used as a key in the Dictionary<TKey, TValue>, it must not change in any way that affects its hash value.

Basically, it's up to the client to use the type properly - just as it's up to the client to dispose of IDisposable instances, not to use types which aren't designed to be thread-safe from multiple threads without synchronization etc.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • `it's up to the client to use the type properly` I wonder how many bugs exist world-wide due to class designs that don't follow common/conventional contracts. – Eric J. Feb 10 '16 at 20:02
  • @EricJ.: Sure, some people will abuse it - but I would rather it went that way round than people who would use the type *properly* (not mutating after using in a dictionary) but can't because the type decided to "play it safe" by violating the documented contract. – Jon Skeet Feb 10 '16 at 20:54