Do I need to override GetHashCode() on reference types?
Asked Answered
D

2

23

I read most questions on StackOverflow with regards to GetHashCode. But I am still not sure whether I have to override GetHashCode on reference types. I picked up the following from someones answer in another question:

Object.GetHashCode() uses an internal field in the System.Object class to generate the hash value. Each object created is assigned a unique object key, stored as an integer,when it is created. These keys start at 1 and increment every time a new object of any type gets created.

If this is still true in .NET Framework 3.5 (can someone please confirm?), then the only problem I see with the default implementations of reference types is that the hash code will have a poor distribution.

I'll break up my questions:

a) So it it recommended to override GetHashCode too if it is used in a Dictionary or does the default implementation perform just fine?

b) I have reference types where it would be easy to do since they have fields that identify them uniquely but what about those reference types where all members are also reference types. What should I do there?

Duffie answered 20/4, 2009 at 18:15 Comment(0)
C
20

You only need to override GetHashCode() on reference types if you override Object.Equals().

The reason for this is simple - normally, 2 references will always be distinct (a.Equals(b)==false, unless they're the same object). The default implementation of GetHashCode() will provide 2 distinct hashes in this case, so all is good.

If you override Equals(), though, this behavior is not guaranteed. If two objects are equal (as per Equals()), you need to guarantee that they'll have the same hash code with GetHashCode, so you should override it.

Camelopardus answered 20/4, 2009 at 18:26 Comment(1)
Just a side note, if you override GetHashCode on a reference type, better make sure that object is immutable. Otherwise you might lose it in the HashTable if it's contents change.Overmeasure
G
0

I just did a sample test, and I do not see how it starts at 1 and gets increment.

for (int i = 0; i < 16; i++)
{
    object obj = new object();
    Console.Write(obj.GetHashCode() + " ");
}

with these results:

45653674 41149443 39785641 45523402 35287174 44419000 52697953 22597652 
10261382 59109011 42659827 40644060 17043416 28756230 18961937 47980820

In fact, using Reflector, I only could see this:

internal static extern int InternalGetHashCode(object obj);

So how it really happens is a mistery to me (there might be a pattern, but I am not going to dig deeper at this point -- maybe some sort of "pseudo random number" algorithm?). Somebody from the CLR team could answer that.

As for the other questions, Reed actually beat me to the punch re: GetHashCode and Equals. The MSDN page describes it with few more gory details, just in case.

Greig answered 20/4, 2009 at 18:36 Comment(3)
It depends...in .NET 1.1 and 1.0 we have other algorytm than in .NET 2.0. If I'm not wrong, this is a random generator in 2.0.Bloodred
Yeah, I didn't see how it looks in any earlier version. I just tested 3.5 as he was asking. And yeah, I think it is a random generator (hence my link to one).Greig
InternalGetHashCode is mapped to an ObjectNative::GetHashCode function in the CLR, which content is visible in the top answer of this article.Sectionalize

© 2022 - 2024 — McMap. All rights reserved.