Thursday, October 11, 2007

How to Improve Collection Initializers

I think I'm starting to traverse the Linq/Orcas circle of (software) life, because I finally hit something that I don't like and that I couldn't work around. So far, anyway - maybe someone out there can tell me where I'm going wrong.

 

You may know that in the Orcas version of C#, they've added support for initializing collections via the funky new object initialization syntax. You can read about it here. The issue that I'm running into has to do with the fact that I'd like to initialize a collection in an object initialization expression, but I'm using XLinq to do it, and as a result I'm getting a compiler error.

 

See, I can get this to work:

 

Person craig = new Person

{

  Name = "Craig",

  Age = 35

  Children =

  {

     new Person

     {

        Name = "Ellen",

        Age = 2.9

     },

     new Person

     {

        Name = "TBD",

        Age = -0.4

     }

  }

}

 

But because this is just a simple example and in my real code I don't know the collection items at compile time, what I really want to do something is like this:

 

Person craig = new Person

{

  Name = "Craig",

  Age = 35,

  Children =

  {

     GetProgeny("Craig Andera")

  }

}

 

Where the Person class is the obvious implementation, and GetProgeny returns IEnumerable<Person>. Without doing anything else, I get a compiler error saying that Collection<Person> does not contain an overload of Add that accepts an IEnumerable<Person>, which makes perfect sense given that the collection initialization syntax is just shorthand for a bunch of calls to Add.

 

The part that sucks is that I can't get this to compose with extension methods to get what I want. That is, I'd like it if I were able to define an extension method like this:

 

public static void Add(this ICollection<Person> collection, IEnumerable<Person> items)

{

   foreach (Person item in items)

   {

      collection.Add(item);

   }

}

 

But that doesn't work. I'm not sure why, but here's the list of things I hope it is, in decreasing order of desirability:

 


  1. I'm doing something wrong.

  2. It doesn't work and there's a good reason.

  3. It doesn't work and there's no good reason.

 

Anyone have any idea which it is?

 

Update: I should have said right up front that Children is a read-only property of Person. I always make my collections read-only, and would prefer to do so in this case as well.

Tuesday, October 9, 2007

Add Using Statement in Visual Studio 2008

Update: Apparently this has been available since VS2005. Who knew? Other than the people that commented, of course. Certainly not me. :)

 

Update #2: So, the "organize usings" menu item that I happened to show in the screenshot alphabetizes the using statements. Also very nice, although I'd like it better if it didn't remove the line breaks I put between groupings. Still, nice. You can also remove unused using statements. Here's the menu:

 


 

Jon Flanders showed this to me the other day. In Visual Studio 2008, if you've just added a class for which you haven't yet added the corresponding using statement to bring the namespace into scope, you can hit control-dot, and up pops the following menu:

 


 

And sure it enough it pops a "using System.Collections;" in up at the top of the file. Very nice. Better still if it would put it in alphabetical order, but I seem to recall that the order of using statements is significant when Linq is in play, so maybe they couldn't do that.

 

You can also access it via the right-click menu: