Tuesday, August 29, 2006

After this evening's Northwest Ohio .NET User Group meeting, Jason Follas and I met up at Tony Packo's for a bit of post-meeting hangtime. In our conversation, Jason admitted his frustration at not being able to write code like this using C# generics:

using System;
using System.Collections.Generic;

static class Program
{
  static void DoSomethingWithList(List<> list) { }

  static void Main(string[] args)
  {
    List<string> stringList = new List<string>();
    List<int> intList = new List<int>();

    DoSomethingWithList(stringList);
    DoSomethingWithList(intList);
  }
}

Unfortunately, that code doesn't compile. The problem is that List<> has to have its "T" type parameter filled in. To solve this dilemma, make "DoSomethingWithList" a generic method like this:

static void DoSomethingWithList<T>(List<T> list) { }

Now, the list parameter will be of type List<T> where T is filled in when the DoSomethingWithList method is called. Hence, we can write code like this:

List<string> stringList = new List<string>();
List<int> intList = new List<int>();

DoSomethingWithList<string>(stringList);
DoSomethingWithList<int>(intList);

IMO, the calling code isn't very elegant with the angle brackets added to DoSomethingWithList. Fortunately, the C# compiler will infer the actual types of generic type parameters if you don't fill them in. I'm currently working on an article that explores this feature in detail because I don't see many people using it and, frankly, it is a life saver for cleaning unwanted angle-brackets out of perfectly readable code. Here is the code again using compiler inference:

using System;
using System.Collections.Generic;

static class Program
{
  static void DoSomethingWithList<T>(List<T> list) { }

  static void Main(string[] args)
  {
    List<string> stringList = new List<string>();
    List<int> intList = new List<int>();

    DoSomethingWithList(stringList);
    DoSomethingWithList(intList);
  }
}
posted on Tuesday, August 29, 2006 9:26:02 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3]

kick it on DotNetKicks.com
Wednesday, August 30, 2006 2:31:10 AM (Eastern Standard Time, UTC-05:00)
Interesting post!

I just did something with list. But in my case the method is public.

When the line
static void DoSomethingWithList...

is changed to
public static void DoSomethingWithList...

and Code Analysis is run, it results in a CA1004 Microsoft.Design Warning "GenericMethodsShouldProvideTypeParameter"

Do you know a way to solve this?
Wednesday, August 30, 2006 7:19:15 AM (Eastern Standard Time, UTC-05:00)
Thanks for your comment. I've posted my response as a new blog entry here: http://diditwith.net/PermaLink,guid,298bf819-cb11-4443-b721-042d43b55b22.aspx.
Wednesday, August 30, 2006 8:45:53 AM (Eastern Standard Time, UTC-05:00)
The danger of using inference is if at a later date you need a non generic method of DoSomethingWithList say for interop, you will have to go and add your brackets back in.

In my opinion the real issue with generics and polymorphisim isn't your example of a generic method, but when you want to make a collection of generic list objects, the only real way I've found is to use interfaces, and fairly ugly type checking.

// replace {} with angles, your editor doesn't appear to allow code snippets
List{string} MyStringList = new Lst{string}();
List{int} MyIntList = new List{int}();
Dictionary{string, Lst{}} MyListCollection = new Dctionary{string, List {}}();

MyListCollection.Add("strings", MyStringList);
MyListCollection.Add("ints", myIntList);

But sadly this level of polymorphisim doesn't exist, I was really hoping with anonymous types becoming official in C# 3.0 that they would be able to overcome this.
John Gooding
Comments are closed.