OdeToCode IC Logo

Generic Gotchas

Thursday, July 15, 2004
The introduction of generics will be a welcome addition to C# and VB in 2.0, except the change is little more disruptive than I would have thought. Consider the current use of Hashtable:

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()
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?

Andy Thursday, July 15, 2004
I wonder why they didn't just return a constant iterator pointing to &quot;end()&quot; like the STL does rather than throw an exception? Then use a first and second for data access. IE make it work like so:
<br>Dictionary&lt;string, string&gt; lastNames = new Dictionary&lt;string, string&gt; ();
<br>Dictionary&lt;string, string&gt;::iterator iter;
<br>string name(&quot;&quot;);
<br>lastNames.Add(&quot;Beatrice&quot;, &quot;Arthur&quot;);
<br>lastNames.Add(&quot;Lucille&quot;, &quot;Ball&quot;);
<br>iter = lastNames.find(&quot;Audrey&quot;);
<br> lastNames.Add(&quot;Audrey&quot;, &quot;Hepburn&quot;);
<br> //then access data in normal iterator style
<br> iter = lastNames.find(&quot;Audrey&quot;);
<br> name = iter.first;
Scott Allen Thursday, July 15, 2004
When you have a container of integers, then it really returns an integer, not the address of an integer ala C++. I think that is the major sticking point, because there is no integer value that can represent &quot;I didn't find it!&quot;. :/
fermaint Thursday, March 24, 2005
i want to know what and where does this name come from?
Scott Thursday, March 24, 2005
Which name, fermaint?
Moye Monday, June 6, 2005
u suck
Comments are closed.