Fun with Generics in Whidbey

I thought I’d share a little of my “app building” fun with you folks.  Just for giggles I wrote a command line tool that lists the most frequent commentors on CLR related blogs.    Most of the code is screen scraping and not that interesting (I understand that Scott is working on getting some great new web services to make this easy as pie).  But there is a bit that uses the new generic collections that I thought would be interesting to share with you.  

 

All of this is on a current Whidbey build, so no promises about this working on the PDC bits.

 

Part 1: The tally.  In this section of code I am keeping a count of how many times each person has commented.  I love the strong typing generics gives me, notice how pretty this line looks:

tally[name]++;

It is unfortunate that I have to have a special case for the first time an entry is added, but I think that makes sense for a general purpose collection such as Dictionary.  

Dictionary<string, int> tally = new Dictionary<string, int>();

List<Uri> entries = GetEntryUris(DateTime.Parse("2/01/2004"), DateTime.Now);

foreach (Uri entry in entries)

{

      foreach (string name in GetComments(entry))

      {

            if (tally.ContainsKey(name))

            {

                  tally[name]++;

            }

            else

            {

                  tally.Add(name, 1);

            }

      }

}

Part 2: The sort.  I needed to do something kind of odd – sort the dictionary by its values rather than its keys.  I do this to get a list in the order of most frequent commentor to least frequent commentor.  Not something even SortedDictionary can support.  I considered writing my own collection for this, but given that I wanted to dogfood our stuff I elected to copy the items into a List<T>. It is a O(n) thing, but fine to do once before I output the results.

I then use one of the new “functional” members on List<T> that works nicely with C#’s anonymous methods.  I am sure we could have some good debates source code formatting for this one.  

I took a look at the IL for this section – very interesting, maybe something we can get Eric or his comrades to blog about?

     

List<KeyValuePair<string, int>> l = new List<KeyValuePair<string, int>>(tally);

l.Sort(

   delegate(KeyValuePair<string, int> obj1, KeyValuePair<string, int> obj2)

{

      return obj2.Value.CompareTo(obj1.Value);

      }

);

Part 3: The report.  The report itself is very easy.   

foreach (KeyValuePair<string, int> k in l)

{

      Console.WriteLine("{0}={1}", k.Key, k.Value);

}

 

As a side note, I predict that usage of C#’s using statement for compile-time type aliasing will dramatically increase as a result of generics usage like what I describe above.  Consider how much cleaner this code is and it compiles to the exact same IL:

 

using NameCount = System.Collections.Generic.KeyValuePair<string, int>;

List<NameCount> l = new List<NameCount>(tally);

l.Sort(delegate(NameCount obj1,NameCount obj2)

{

      return obj2.Value.CompareTo(obj1.Value);

});

foreach (NameCount k in l)

{

      Console.WriteLine("{0}={1}", k.Key, k.Value);

}