Title: Dictionaries and GetHashCode()
Slug: dictionaries-and-gethashcode
Date: 2008-12-02 11:21:00
Author: Kartones
Lang: en
Tags: Development, C#, .NET, Patterns & Practices
Description: A lesson learned about the importance of overriding GetHashCode() method when comparing objects in .NET.

 <p>Yesterday I had a small problem while implementing a class that had a <font face="Courier New">Dictionary&lt;key, value&gt;</font> , where the key was a small class (containing a name and a version code).</p> <p>I had implemented this override for Equals:</p> <p><font face="Courier New">      <font color="blue">public override bool </font><font color="black">Equals(</font><font color="blue">object </font></font><font face="Courier New"><font color="black">obj)<br>        {<br>            </font><font color="blue">if </font><font color="black">(obj </font><font color="blue">is </font></font><font face="Courier New"><font color="black">Key)<br>            {<br>                </font><font color="blue">if </font><font color="black">(</font><font color="blue">this</font><font color="black">.name </font><font color="blue">== </font></font><font face="Courier New"><font color="black">((<font face="Courier New"><font color="black">Key</font></font>)obj).name &amp;&amp;<br>                    </font><font color="blue">this</font><font color="black">.version </font><font color="blue">== </font></font><font face="Courier New" color="black">((<font face="Courier New"><font color="black">Key</font></font>)obj).version)<br>                    </font><font face="Courier New" color="blue">return true;<br>                else<br>                    return false;<br>            </font><font face="Courier New" color="black">}<br>            </font><font face="Courier New"><font color="blue">else<br>                throw new </font><font color="black">ArgumentException(</font><font color="#808080">"Can only compare with Key objects"</font><font color="black">)</font></font><font face="Courier New"><font color="blue">;<br>        </font><font color="black">}</font></font></p> <p>But I left the GetHashCode with the default override:</p> <p><font face="Courier New">        <font color="blue">public override int </font></font><font face="Courier New"><font color="black">GetHashCode()<br>        {<br>            </font><font color="blue">return base</font><font color="black">.GetHashCode()</font></font><font face="Courier New"><font color="blue">;<br>        </font><font color="black">}</font></font></p> <p>I had unit tested the class isolated and everything was working fine.</p> <p>Then, I used this class into another one, and my new unit tests for the new class started to fail when performing a <font face="Courier New">Contains()</font> call, having the same values for name and version...</p> <p>After digging <a href="http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx">on MSDN</a>, I found this:</p> <p>"The default implementation of the GetHashCode method does not guarantee unique return values for different objects. Furthermore, <b>the .NET Framework does not guarantee the default implementation of the GetHashCode method</b>, and the value it returns will be the same between different versions of the .NET Framework. Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes."</p> <p>In my situation, it was acting weird the opposite, generating different hash codes for Key objects with exactly the same values (but different memory positions).</p> <p>So, I did a quick rewrite of the <font face="Courier New">GetHashCode()</font> method...</p> <p><font face="Courier New">        <font color="blue">public override int </font></font><font face="Courier New"><font color="black">GetHashCode()<br>        {<br>            </font><font color="blue">return </font><font color="black">(name + version).GetHashCode()</font></font><font face="Courier New"><font color="blue">;<br>        </font><font color="black">}</font></font></p> <p>And now it works perfectly. If Key's name and version are the same, the hash code will be the same and this calls will return true: <font face="Courier New">myColl.Contains(new Key("myName", "1.0");</font></p> <p> </p> <p><b>Lesson learned</b>: If you are going to compare objects, remember to override GetHashCode().</p>
