October 28, 2005

Migrating from Hashtable to Dictionary<K,V> - beware of a difference in the indexer behavior

I'm migrating lots of code to the .NET 2.0 nowadays and wanted to warn my readers about one particularly nasty migration issue. When moving from Hashtable to Dictionary<K, V> look carefully at the indexer usage - there is a runtime breaking change here. With Hashtable when you do myhashtable[mykey] and ...

When working with Hashtable it's quite natural to write code like this:

Foo f = (Foo)myhashtable[mykey];
if (f != null) 
{
  //work with f
}
When moving to Dictionary<K, V> this code would compile but will throw KeyNotFoundException whenver mykey isn't in myhashtable. You gotta change this code.

There are two options here. First - every time you need to get a value out of a dictionary make sure it contains the key:

if (mydictionary.ContainsKey(mykey))
{
  Foo f = mydictionary[mykey];
  //work with f
}
This is bad approach. Not only it performs lookup twice, it still can throw an exception in multithreaded applications.

Much better approach (explicitly designed to cover the whole issue) is to leverage Dictionary.TryGetValue() method:

Foo f;
if (mydictionary.TryGetValue(mykey, out f))
{
  //work with f
}
Dictionary.TryGetValue() method returns true if the Dictionary contains an element with the specified key; otherwise, false. Moreover:
If the key is not found, then the value parameter gets the appropriate default value for the value type TValue; for example, 0 (zero) for integer types, false for Boolean types, and a null reference (Nothing in Visual Basic) for reference types.

Use the TryGetValue method if your code frequently attempts to access keys that are not in the dictionary. Using this method is more efficient than catching the KeyNotFoundException thrown by the Item property.

This method approaches an O(1) operation.

Ok, fine solution, but still remember than when moving from Hashtable to Dictionary<K, V> you have to check very carefully every single indexer usage to spot nonexisting key cases.