Behind this dropdownlist is some of the coolest code I have written for ages!

How can that be? Well, I learnt a lot about generics and anonymous delegates in the process… if you want to see some totally geeky code, read on,
Of course, there is a chance that for most of you this is all old hat, in which case you can go back to sleep…it was new to me for sure.
Still awake?
So, first of all, I had a lot of fun retrieving the data that populates this list.
The data that drives this DropDownList is a list of what I call FeatureGroups (the list has 2 elements, Defects and Manage Projects), which has a Master Detail relationship to Features (a FeatureGroup contains 0 or more Features). It is in fact a List<AFFeatureGroup>, where each FeatureGroup contains a List<Feature>. Feature references back to its containing FeatureGroup through a FeatureGroupID member.
When I go to populate this list of FeatureGroups, I want to do it in one database call, so what I fetch is a flattened out Result Set that contains { FeatureGroup.ID, FeatureGroup.Name, Feature.ID, Feature.Name }.
I then need to iterate through that result set and for each FeatureGroup.ID I find, see if I already have created a FeatureGroup for that ID, if not, create it, then add the Feature to that new or existing feature group.
This is a standard pattern, you would have a list of your FeatureGroups in one hand, and be adding to it and searching in it as you go while looping through the flattened result set. Well here is how to spice it up!
It turns out that the generic List<T> type has a Find<T>( Predicate<T> match ). The predicate method is a method that takes a Predicate<T> and returns a bool. This method passed in as this parameter is called once on each item in the list, and the first time it returns true, that will be the item returned by Find. And, when invoking Find, you can pass in an anonymous delegate. In other words, you don’t have to pass in a new Predicate<T>( myCompareMethod ), you can just pass in the implementation of myCompareMethod…
This is how it looks:
private static List<AFFeatureGroup> GetFeatureGroupsFromFeatures( List<AFFeature> features )
{
List<AFFeatureGroup> result = new List<AFFeatureGroup>();
foreach (AFFeature f in features)
{
AFFeatureGroup fg = result.Find(
delegate(AFFeatureGroup featureGroup) { return featureGroup.ID == f.FeatureGroupID; });
if (fg == null)
{
fg = new AFFeatureGroup(f.FeatureGroupID, f.FeatureGroupName);
result.Add(fg);
}
fg.Features.Add(f);
}
return result;
}
Let me break this down:
- The method receives a List of AFFeatures, this is the flattened out result set containing one Feature in each row with its FeatureGroup as well.
- The first line, result = new List<…> just creates an empty list of AFFeatureGroups that I will be returning once populated
- Then, I loop through all the features that I have fetched
- In the loop, I call the Find method of List<AFFeatureGroup>, passing my find implementation. Note two things:
o a) I declare that the anonymous delegate accepts a AFFeatureGroup, which is mandated by the signature of Predicate<T>, as this code will be called once for each AFFeatureGroup in the list until a match is found
o b) Inside the implementation curly braces, I can compare the featureGroup.ID of this passed in AFFeatureGroup to the value of f.FeatureGroupID. Think about that some! This is the powerful part! It’s kind of like in Delphi when you could pass in the address of a local nested method and that method would have access to any local variables or parameters in the enclosing method scope. The variable f is in the loop that encloses the call to Find, so in effect, what the compiler does is it captures the current value of f when creating the anonymous method, and makes it available inside the method body! Basically you have a dynamically created nested local method inside of the for loop. This is awesome compiler magic!
- OK, so if a match is not found, I create a new AFFeatureGroup, and I then add it to the result list
- If a match was found, or if I just created one, I can now add the feature itself to the feature group
And that is it: with this simple set of code I am doing a pretty complex construction of objects! This is what the language features of C# 3.0 will be taking one step further, where I will be able to use type inference to get rid of even more code above, for instance the declaration delegate(AFFeatureGroup featureGroup) can go away and I will just have a lambda expression there instead.
So, now for geek part 2…. I now have a method that will take a flattened list and build my two dimensional structure, but now I want to cache that list. Well, first I started with the classic approach, I look in the Cache object for a certain key, and if I don’t find it, I go fetch the data from the database (using the method in part 1), and store it in the cache. But this gets so repetitive, and I also wanted to centralize some of the aspects of the caching, like for how long the cached data is kept.
I started off along the lines that my colleague Adam Markowitz pioneered in the Velocity project, where you basically can create a CacheManager class that uses generics to do a type safe cache search. But then I figured if List<T> can accept a Predicate<T> in its Find method, why can’t I write a Cache.Get<T> that also accepts a T Fetcher<T> that will be invoked if there is no cache hit? Of course, Fetcher<T> might need some parameters, so I decided I would need two types of delegate, one that takes no parameters, and one that takes an instance of some arbitrary type D as a parameter (I could have been lazy and used an object instead of D, but what I love about Generics is the type safety it gives you without the performance drawbacks) :
public delegate T Fetcher<T, D> ( D data );
public delegate T ParameterlessFetcher<T>();