Saturday, November 8, 2008

Use expression tree to avoid string literals in "reflecting code" (ReflectionHelper)

Reflection is a very useful mechanism letting us build very smart and flexible solutions. It is used in many places in .Net framework, for instance in Windows Forms to identify bound members or in Workflow Foundation to pass some parameters to workflow instance and many others. Those two samples have one common thing, we have to use string literals in code to identify type members such as properties. And of course it's not a problem if the types we use are not changing, it means once specified, member won't be changed in the future. Like which shouldn't change like .net framework types (it shouldn't be change cause of backward compatibility).

Lets imagine that we bind one property of our business object to a TextBox's property Text and one day during refactoring someone else changes the name or the type of the property or even worse - deletes it. The code will compile correctly but we can't be sure how it will work at runtime because it depends on the sort of change. Maybe some exception will be thrown, maybe everything will look fine but the property won't be set after modifying text in the TextBox or maybe all will work just fine. Such bugs are very unpredictable and very hard to find. Wouldn't it be nice if we could know just after change about possible problems (compilation failed). Sometimes we know than the property is used in many places in the code, so we rename it via our IDE (for instance in Visual Studio we can choose option 'Refactor -> Rename...') and we want be sure that everything works fine. Is this possible ?

Today I'll show you a utility class called ReflectionHelper giving us the ability to realize mentioned scenario. Currently when we extract information about property via reflection we write something like this:

public class SomeClass
{
    public int InstanceProperty { get; set; }
    public static int StaticProperty { get; set; }
}

PropertyInfo property1 = typeof(SomeClass).GetProperty("InstanceProperty");
PropertyInfo property2 = typeof(SomeClass).GetProperty("StaticProperty");

With ReflectionHelper the same code can be written like this:

PropertyInfo property3 = ReflectionHelper.GetProperty((SomeClass o) => o.InstanceProperty );            
PropertyInfo property4 = ReflectionHelper.GetProperty(() => SomeClass.StaticProperty);

This is exactly what we wanted to achieve. We have created instance of PropertyInfo class without using any string literals. Now when we manually change the name of a property in one place, the code won't compile. If you rename it by 'Rename...' option in VS, code inside lambda expression will be changed too.

Now, lets see how ReflectionHelper works. ReflectionHelper is a static class with 2 methods extracting information about given property. One for static properties and one for instance. The implementation is quite short and looks like this:

public static PropertyInfo GetProperty<TObject,T>(Expression<Func<TObject,T>> p) 
{ 
    return GetPropertyImpl(p); 
}
public static PropertyInfo GetProperty<T>(Expression<Func<T>> p) 
{ 
    return GetPropertyImpl(p); 
}
private static PropertyInfo GetPropertyImpl(LambdaExpression p)
{
    return (PropertyInfo)((MemberExpression)(p.Body)).Member;
}

The key point to understand how the code works is a new feature of C#3.0 called expression trees. In new version of C# we can use lambda expression in code. There are two kinds of lambda expression where the body of the method is a single expression ( x => x.ToString() ) or one or many statements (x => {return x.ToString(); } ).

Func<int, int> expressionBody = (a) => a + 1;
Func<int, int> statementBody = (a) => { return a + 1; };

In many places we use lambda with single expression body just because it's shorter but there is a scenario when we have to use it. Generally when compiler sees lambda expression in code it's treated as an anonymous method, but lambda expression can be also used to build expression trees. Lets look at the example:

Expression<Func<int, int>> exp1 = (a) => a + 1;
Expression<Func<int, int>> exp2 = (a) => { return a + 1; }; 
// Error: A lambda expression with a statement body cannot be converted to an expression tree

Ok, but what is an expression tree actually? When compiler sees lambda with expression body not in the context of delegate type but in the context of special generic type 'System.Linq.Expressions.Expression<TDelegate>' a lot of code is generated behind the scenes.

ParameterExpression p;
Expression<Func<int, int>> exp1 = Expression.Lambda<Func<int, int>>
(
    Expression.Add // body
    (
        p = Expression.Parameter(typeof(int), "a"),
        Expression.Constant(1, typeof(int))
    ),
    new ParameterExpression[] { p } // parameters
);

The code of lambda expression is interpreted and translated into code that actually builds its structure. Use 'Expreesion Tree Visualizer' to better visualize the structure of expression tree.

When we look back to implementation of GetProperty method we can see that it takes an expression tree as a parameter. Inside the the method we make some assumptions about the structure of tree so we know exactly where information about property is stored. Of course if the structure of the tree would look differently, some exception could be thrown. The same technique can be used to extract information about fields, methods and constructors (ReflectionHelper has appropriate functionality). In case of getting information about the methods there are different ways of doing it.

public class SomeClass
{
    public void InstanceMethod(int i) { }
}

Instead of writing literal call

var method = typeof(SomeClass).GetMethod("InstanceMethod");

use ReflectionHelper like this:

var method = ReflectionHelper.GetMethod<SomeClass,int>(o => o.InstanceMethod);

or like this:

var method = ReflectionHelper.GetMethodByCall<SomeClass>(o => o.InstanceMethod(1));

The implementation looks like this:

public class ReflectionHelper
{    
    public static MethodInfo GetMethodByCall<TObject>(Expression<Action<TObject>> expression) 
    { 
        return GetMethodByCallImpl(expression); 
    }
    public static MethodInfo GetMethodByCall(Expression<Action> expression) // for static methods 
    { 
        return GetMethodByCallImpl(expression); 
    }
    private static MethodInfo GetMethodByCallImpl(LambdaExpression expression)
    {
        return ((MethodCallExpression)expression.Body).Method;
    }    
    
    public static MethodInfo GetMethod<TObject, T>(Expression<Func<TObject, Action<T>>> expression) 
    { 
        return GetMethodImpl(expression); 
    }
    public static MethodInfo GetMethod<T>(Expression<Func<Action<T>>> expression) // for static methods 
    { 
        return GetMethodImpl(expression); 
    }
    private static MethodInfo GetMethodImpl(LambdaExpression expression)
    {
        return (MethodInfo)((ConstantExpression)((MethodCallExpression)((UnaryExpression)expression.
            Body).Operand).Arguments.Last()).Value;
    }
}

When we use GetMethod method we don't need to write methods parameters inside brackets but we need to provide their types as generic method arguments (if parameters exist or method returns something). In the second approach we just write code executing method inside lambda expression. The code is never executed so we don't have to pass any correct arguments. These two approaches have one common disadvantage. When we change the signature of the method by changing parameters or return type, we need to change the code reflecting that method too. Maybe there is some solution but I couldn't find it :(

Full implementation of ReflectionHelper class with code presenting many different scenarios of using them can be found here. In the next post I'll show you how the ReflectionHelper is used in real life :) Stay tuned!

No comments: