November 2, 2008 11:00
Microsoft Visual Studio 2010 and .NET 4.0 is available for download [1]. You probably know that but anyway. We can touch something real, more than a year prior to the actual release! A lot of room for MS to fix bugs and adapt to community requests – as Tom Waits sings, the quality goes in before the name goes on, eh?
The flip side of this event is that, yes, we still have some time to catch up with the existing language features of .NET.
My hobbyhorse.
It's easy to get amazed with something new and shiny while overlooking the usual things that yet have a lot of unused power. So let's talk about lambda expressions and their practical use.
Design By Contract.
If you're a design by contract kind of person, you probably start your methods from checking if the parameters are valid. A method may require non-null params and non-empty strings and so on – if it's not the case, you simply return or throw an exception.
Usually it's done via a series of if statements or using an ad hoc helper with all this range of ThrowIfSomething methods.
private void WriteCarName(Car car)
{
if (car == null)
throw new ArgumentNullException("car");
if (car.Name == null)
throw new ArgumentNullException("car.Name");
...
}
Expression Trees and Lambdas.
But we can wedge lambdas into these checks [2], making the validation more concise:
private void WriteCarName(Car car)
{
Check("car", () => car != null && car.Name != null);
...
}
And, assuming car.Name is null, get the result:
If you're not familiar with lambdas and expression trees you probably still can read on and venerate them, but then please visit some more respectworthy websites to get used to the notation and the whole philosophy behind lambdas in C# [3]. The Check method goes here:
private void Check(string parameter, Expression<Func<bool>> test)
{
var predicate = test.Compile();
if (predicate())
return;
string body = test.Body.ToString();
var regex = new Regex(@"\(value\(.*?\)\.");
body = regex.Replace(body, "(");
throw new ArgumentException("Parameter '" + parameter + "' failed the test: " + body);
}
It takes our lambda as an expression tree, compiles it, and if the test fails then validation logic is retrieved from the expression body. We need a regex here (a friend of mine helped with it because I'm not a regex expert by any stretch of imagination), and here's the reason: the compiler creates an autogenerated class for our lambda, so the car parameter gets a slightly different name. Just try the example with and without regex and you'll understand what I mean.
Footnotes.
[1] – You can download VS2010 CTP here. At the end of last week it was not accessible – perhaps the servers crashed, succumbed to a flood of downloaders. Another rumor is that they had to repackage the bits cause someone had left private debugging symbols in the original. Anyway, if anything happens please keep tabs on the feedback page and this post by Othmane Rahmouni.
[2] – All glory should go to Andrew Matthews as all the stuff above was inspired by his using lambdas for DBC and C# by contract ideas. He goes a lot further providing a whole framework for designing by contract in C#, so if you're really interested in the topic – his blog is a good start.
[3] – As for lambdas and expression trees, there is a decent article at codeproject, Eric While has an amazing post though not covering the trees so you'd probably have to go to MSDN for them.