Getting Down with Generics
I recently finished my first "real" Windows Forms app in .NET 2.0, and when I finally got to a "complete" working version I was ready to do some cleanup and refactoring. So, I began combing through my code, reading for things I wasn't completely satisfied with. After correcting a few "magic numbers" type issues, it so happened that Brian came by my desk. Brian is a younger colleague here, really sharp guy, great attitude--one of the ones who "gets it". And he points out that I'm using "old school" Collection classes, when I could be using Generics. So that's silly to begin with; I wasn't using something it made sense to use, simply out of unfamiliarity with the technique. But at this point I also realized that I had a bug in my code due to the improper usage of the ArrayList.Contains() method (it compares references, not values). Duh. So I quickly turned my attention to replacing my type-insensitive ArrayLists and SortedLists to delightfully type-safe Generic collections.
Actually the process was not terribly difficult. The auto-refactoring capabilities of VS2005 do much of the grunt work of altering references for you. So once you select the appropriate type from System.Collections.Generic, it's pretty elementary to feed it the type you want the Collection to be. In my case, the List type was sufficient (as I didn't really need a typed key, or sorting capabilities, or some of the more elaborate functionality available in other members).
The one thing that did trip me up at first was that I needed to verify whether elements already existed within my collections prior to adding them--which is what I was trying (unsuccessfully) to do with ArrayList.Contains(). But, again, Brian came to the rescue and this was pretty easily resolved. The collection element classes I was working with needed IComparer<> classes to go with them. The IComparer<> interface is very easy to implement, primarily consisting of the Compare( x, y) method. In implementing this method, there are some basic rules that allow you to sort out the process of actually comparing the two objects. But in my particular case, the extent of comparison possibly was greater than what I needed, since I really only cared if the element being passed in already existed in the collection. So my implementation was extremely simple.
Once the IComparer<>.Compare() implementations were defined for my collection element types, the matter remained of determining which method of the List<> type would perform the task at hand. As I mentioned, the reference comparison done by ArrayList.Contains() wasn't doing it for me. At Brian's suggestion, I used the BinarySearch() method of the List<> type. It allowed me to pass in the element I was looking for, and used my IComparer<> implementation to return 0 if not found. A non-zero return value indicated that it was already there. As a sidebar, my implementation of the Compare() method could have told me more about a found element's relative value, but as noted this was not really important in this context...
Anyway, the somewhat goofy side of this exercise was the limited way in which my app legitimately benefited from using Generics. The number of collection elements in this app is going to remain relatively small--certainly not getting into the territory where the speed boost yielded by using Generics would impact performance. However, using Generics did allow for more elegant code, as several "for" loop constructs gave way to slicker "foreach" statements, and I was happier in general with the explicit type-safety of the Generic collections.


Interesting post
Interesting! See my blog on Collections, Generics, and the Theory of Sets.