Hashtable lastNames = new Hashtable(); lastNames.Add("Beatrice", "Arthur"); lastNames.Add("Lucille", "Ball"); object name = lastNames["Audrey"]; if (name == null) { lastNames.Add("Audrey", "Hepburn"); }
Now here is how it might look after an porting to use the generic type Dictionary<K,V>:
Dictionary<string, string> lastNames; lastNames = new Dictionary<string, string> (); lastNames.Add("Beatrice", "Arthur"); lastNames.Add("Lucille", "Ball"); // the next line throws KeyNotFoundException string name = lastNames["Audrey"]; if (name == null) { lastNames.Add("Audrey", "Hepburn"); }
In Beta 1 the indexer throws an exception if the given key does not exist in the collection. If this is not desirable behavior, you can use the ContainsKey method to check safely if a given key exists. The current behavior makes porting code based on Hashtable to Dictionary<K,V> a bit trickier.
I think the current behavior is justified. What would happen with a Dictionary of integer values when you pass a key that does not exist? There is no possibility of returning null for a value type, and returning a default value (0) seems misleading and bug-prone.
Another gotcha is in the second sentence of the documentation for every generic type:
This class is not CLS-compliant
The question is: Do I care?
I’ve read articles about how being CLS compliant will allow for interoperability with a wider range of .NET languages. This could be important for library designers targeting the 0.4% of the market using Cobol.NET and Fortran.NET. I did a quick test to see the impact on the other 99.1%. First, I put the following in a C# class library:
public class Class1 { public Dictionary<string, int> GetDictionary() { Dictionary<string, int> foo = new Dictionary<string, int>(); foo.Add("test", 2112); return foo; } }
Next, a quick VB program to use the C# class. (I was a little worried I might have to dig to find generics syntax for VB, but my fingers had a spasm and intellisense auto-completed the entire program. It was amazing. Did I mention my cat wrote a Tetris knock-off with Whidbey last week?).
Sub Main() Dim c As New ClassLibrary1.Class1 Dim bar As Dictionary(Of String, Int32) bar = c.GetDictionary() Console.WriteLine(bar("test").ToString()) End Sub
It all just works.
For the applications I work on, generics are powerful enough to sacrifice CLS compliance. I imagine this will be the case for the majority of developers. Porting an existing codebase heavily into collections to the generic types won’t be automatic, but nothing to sweat over if all the unit tests are written, right?