Thursday 15 January 2009

Collection Initializers, Events and Variables

Collection initializers are very neat. Great for regular code, but also quite handy for writing minimal demo code... for example, consider this recent winforms example for displaying a button on a form:

   [STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form
{
Text = "Hello world",
Controls =
{
new Button
{ Text = "Change title" }
}
});
}

What's wrong with that? Events and variables: collection initializer syntax doesn't allow you to subscribe events, and even if it did, we wouldn't have a convenient reference for each of the items (the form, the button, etc) to talk to.

The good news is that there is a simple fix; it isn't especially magic or clever - I'm simply repeating it here becaues I've seen a couple of people surprised by it. Basically, we can get the collection initializer to assign some variables for us - but we need to be a little sneaky because the language specification deliberately disallows assignment expressions from collection initializers (to avoid ambiguity with member assignments in object initializers). So how? Simple: brackets:

   [STAThread]
static void Main()
{
Application.EnableVisualStyles();
Button button;
Form form = new Form
{
Text = "Hello world",
Controls =
{
(button = new Button
{ Text = "Change title" })
}
};
button.Click += delegate
{
form.Text = "New text";
};
Application.Run(form);
}

Points to note:

  • We declare variables for the objects of interest
  • We assign the variable in the collection initializer, but surround the assignment in brackets (making the result a non-assignment expression)
  • We still get definite assignment checking for free
  • We can "capture" the variables in anonymous methods / lambdas as normal
  • We can assign multiple variables in the same overall statement

Not huge, but one of those small things that might make things easier! The same approach will work with any collection initializer - winforms is just a commonly understood example.