Sunday 25 January 2009

Extension Methods in .Net 2.0

I was recently reading C# in Depth by Jon Skeet and also playing with Rhino Mocks by Oren/Ayende and was struck by the power and simplicity of both Extension Methods and also Lambda expressions. These are both C# 3 compile time features which I thought would be very useful to me in my C# 2 application which sounds like a shame. Until that is I came across this blog by Daniel Moth who describes how to use Extension Methods in C# 2.0. [Actually, as Jon Skeet has pointed out, I mean using C#3 in a .Net 2.0 assembly, see his comment for a link that explains the difference.]

Once you realise that both of these features are purely compiler trickery then all you need to do is figure out how to get them to work in .Net 2 assemblies. Daniel describes how to get Extension Methods working, by defining an Attribute that is usually available to the C# compiler when building a .Net 3.0 assembly (ExtensionAttribute). The attribute needs to be defined in the System.Runtime.CompilerServices namespace rather than one of your own.

This tricks the VS2008 C# compiler into thinking that it is compiling to .Net 3 rather than .Net 2, at least as far as Extension Methods are concerned, so now it is happy for you to add the this keyword in the static methods parameter list.

Next came lambda methods, this is also compiler tricks and simply compiles to .Net 2.0 delegate code underneath. Again you need to get the compiler to think that some things not normally available to it in C# 2 are indeed available. In this case, we need a more extensive Action<> delegate. .Net 2 provies Action that allows for an action on a single class with no return value. For what I wanted, Lambdas, we needed the .Net 3 Action class. This allows you to call delegates with return types.
This class can be defined in any namespace.

My reason for wanting these capabilities was to simplify some WinForm validation code we're writing. Imagine we have a ComboBox and want to perform validation everytime the SelectedItem changes. We want to turn the background colour to be Red if there is no selected item, and to green is something in the list has been selected. If we have 3 such combos on a form, we could capture the SelectedItemChanged event for each and perform the set of checks to see if there is a selected item and then colour the backgrounds.

Or we could use an Extension Method. I now have a ComboBoxExtension class which has the following method signature


public static void InitialiseValidation(this ComboBox combo, Color defaultColor, Action rule)


This is an Extension Method on ComboBox (first parameter), defines the default, not selected colour (second parameter) and an arbitary validation rule which returns bool and acts on a ComboBox (third parameter). This means I can write the following code in the WinForm code:


someCombo.InitialiseValidation(MColourFactory.InvalidColour, c => c.SelectedItem != null);


This simply means that when the SelectedItem property on someCombo is null, it will colour the combo the InvalidColour from our colour factory (red in this case).

There are also Extension Methods to add additional rules beyond this first one as well as explicit IsValid methods that use the same rule set.

All of this runs quite happily in a C#, .Net 2.0 assembly using the VS2008 C# compiler to do it, if you're using VS2005 I suspect you're out of luck!


1 comment:

Jon Skeet said...

You need to be slightly careful about the versions here - you can indeed use a lot of the features of C# 3.0 when targeting .NET 2.0, but you can't use them in *C#* 2.0. The difference between language and framework version is pretty important :)

See http://csharpindepth.com/Articles/Chapter1/Versions.aspx for more info, btw.