Sunday 6 July 2008

Using Linq's Expression Trees to Enable Better Refactoring

How many times have you seen code like this:

public DateTime StartDate
{
  get { return this.startDate; }
  set
  {
    this.startDate = value;
    this.RaisePropertyChanged(this, "StartDate");
  }
}

I know I have! There are many areas of .NET development where you are required to specify the name of a property or method as a string. This is fine, but if you rename the property, there is a chance that you will forget to update the string too, which is definitely not good!

.NET 3.5 and Linq introduces a new feature called expression trees in the C#3 compiler. Compilers typically generate an AST (abstract syntax tree) from the code you write, which is then checked and transformed into machine code (or in .NET case, MSIL). By using an expression tree, you tell the C# compiler not to compile your code into MSIL, but instead to create a representation of the code in object form. This tree can then be navigated through methods on the Expression objects.

Using an expression tree, we can simply write a method which will return the name of whichever method or property is being called (I used an extension method):

public static class Extensions
{
    public static string GetPropertyName<T,S>(this T obj, Expression<Func<T,S>> expr)
    {
        return ((MemberExpression) expr.Body).Member.Name;
    }
}

To call this is fairly simple, we rewrite the previous code as:

public DateTime StartDate
{
  get { return this.startDate; }
  set
  {
    this.startDate = value;
    this.RaisePropertyChanged(this, this.GetPropertyName(p => p.StartDate));
  }
}

The code above creates a lambda which returns the value of StartDate method and passes it to the GetPropertyName() method. If this lamdba was to be executed, it would return the startDate, however the GetPropertyName() function never executes the lambda, it simply peeks into the code being called and returns the name of the property.

This technique is starting to be used everywhere and it's so useful. Code as strings is nasty!

Have a great day...

No comments: