Key’s Equality in Hashtables (or who equal to who?)
January 15, 2008
Consider the following simple class:
public class SomeClass
{
uint _id = 125;public SomeClass(uint id)
{
_id = id;
}
public override int GetHashCode()
{
return (int)_id;
}
}
We want to add instance of this class to hashtable, where the key is object’s ID, and the value is object itself. If we doing the following, it works:
SomeClass someClass = new SomeClass(125);
//1.
//========
hashTable[someClass.GetHashCode()] = someClass;
object returnValue = hashTable[125];
The returnValue is exactly our someClass instance. However, using value types as keys as bad, due to boxing each time key is passed to the hashtable. How we can improve this? Well, as known, inside hashtable ‘GetHashCode’ method is being called to determine the key. Therefore we can pass as a key the object itself, and override the ‘GetHashCode’ method (which is exactly what we did). Let’s try this code:
//2.
//===========
hashTable[someClass] = someClass;
SomeClass key = new SomeClass(125);
returnValue = hashTable[key];
If you will run this code, you will see the returnValue is null. So what is wrong? When you trying to retrieve your object from hashtable and passing the key, hashtable using ‘Equals’ method, to find the right key. By default, after confirming the hashcode is the same, it comparing references, so in the code above the result is false. Obvious, the solution is to override the ‘Equals’ method (here is the one possible solution):
public override bool Equals(object obj)
{
return (_id == obj.GetHashCode());
}
If we run this code, that works ok. Now, we want to retrieve the object by passing the ID directly, without creating wrapper around it (as I said before, this is bad because of boxing – don’t do that in production code):
hashTable[someClass] = someClass;
returnValue = hashTable[125];
We overrided the Equals method, so this will work? No, it will not. You see, the hashtable comparing the passed key to the stored keys, and not storing keys to passed one. As a result, the ‘Equals’ method is invoked on the passed key – in our example it’s an integer – and it never equal to SomeClass, ofc. The conlcusion is: if you using your custom classes as hashtable keys, always override ‘GetHashCode’ and ‘Equals’ methods. And remember to use only your classes for the lookup inside the hashtable.
Entry Filed under: General C#. Tags: custom keys, equals, gethashcode, Hashtable, performance.
2 Comments Add your own
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed
1. Another thoughts about hash tables. « Aizikovich Evgeni | March 4, 2008 at 4:33 pm
[...] my atricle about hash table keys I discussed how is bad to use value types as keys (this is applied to non [...]
2.
Sander | May 15, 2009 at 3:57 pm
Thank you VERY much. Was scratching my head why GetHashCode was behaving weirdly.