Using objects as key in HashTable

Author : Ingmar Verheij

A HashTable can be used to store a collection of key/value pairs. The key object is used to uniquely identify the key/value pair which makes is easy to store data like a database.

The type of the key object which is added to the HashTable is variable. It can be an integer, a string, a GUID etc. Because of the nature of a GUID (a globally unique identifier) it is an ideal candidate for a key object.

If you want to use a combination of two (or more) GUIDS as a key object you can create a class object, but there is a caveat.

Example #1 – How you shouldn’t use it

Let’s take create two GUID objects, called objKey1 and objKey2, and fill them with a GUID.

Dim objKey1 As Guid = New Guid("423baa7b-4f46-4b42-b3e8-498e11099544")
Dim objKey2 As Guid = New Guid("f0bcf839-4349-4ff2-8695-6a91df86cabb")

Now where going to create a hashtable called objHashTable where the key/value pairs are stored.

Dim objHashTable As New Hashtable()

Because we want to store two GUID’s as a key object where going to create a simple class called ValueKey.

Private Class ValueKey
   Public Key1 As Guid
   Public Key2 As Guid
   Public Sub New(Key1ID As Guid, Key2ID As Guid)
       Key1 = Key1ID
       Key2 = Key2ID
   End Sub
End Class

Now let’s add a key/value pair to the hashable

objHashTable.Add(objKey, Date.Now)

The hashtable objHashTable now contains one key/value pair. We can check if the key object we’ve just added is in the hashtable:

Debug.Print("Key found #1 : " & objHashTable.ContainsKey(objKey))

Key found #1 : True

Okay, as expected. Now let’s create a new object key with exact the same content (objKey1 and objKey2)

objKey = New ValueKey(objKey1, objKey2)

Since the content of the key is exactly the same (objKey1 and objKey2 isn’t changed) you expect the key to be present in the hashtable:

Debug.Print("Key found #2 : " & objHashTable.ContainsKey(objKey))

Key found #1 : False

That was NOT the expected result. Although the content of the key object is equal, the hashtable can’t find the key object.

Example #2 – How you should use it

The problem in example 1 is caused by the uniqueness of the KeyValue class. If you compare the two objects with Object.Equals method you’ll notice they are not equal. If the objects are not equal, the key value in the hashtable will never match.

The solution lies in the KeyValue class, it needs an override for the Equals (and GetHashCode) method.

So let’s use the same code as in example 1 but add an override for the Equals and GetHashCode in the KeyValue class.

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim objKey1 As Guid = New Guid("423baa7b-4f46-4b42-b3e8-498e11099544")
    Dim objKey2 As Guid = New Guid("f0bcf839-4349-4ff2-8695-6a91df86cabb")
    Dim objHashTable As New Hashtable()
    Dim objKey As New ValueKey(objKey1, objKey2)
    objHashTable.Add(objKey, Date.Now)
    Debug.Print("Key found #1 : " & objHashTable.ContainsKey(objKey))

    objKey = New ValueKey(objKey1, objKey2)
    Debug.Print("Key found #2 : " & objHashTable.ContainsKey(objKey))
    End
End Sub

Private Class ValueKey
    Public Key1 As Guid
    Public Key2 As Guid
    Public Sub New(Key1ID As Guid, Key2ID As Guid)
        Key1 = Key1ID
        Key2 = Key2ID
    End Sub
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
       If obj Is Nothing OrElse Not [GetType]().Equals(obj.GetType()) Then Return False
       Return (Key1.Equals(obj.Key1)) And (Key2.Equals(obj.Key2))
    End Function
    Public Overrides Function GetHashCode() As Integer
       Return (BitConverter.ToInt32(Key1.ToByteArray, 0) / 2) + (BitConverter.ToInt32(Key2.ToByteArray, 0) / 2)
    End Function
End Class

Key found #1 : True

Key found #2 : True