Replacing Expression.Compile under Windows Phone 7

I recently started porting FluentValidation to Windows Phone 7. This didn’t take much effort as most of the work had already been done when I ported it to Silverlight. However, the one thing that did cause a problem is the lack of expression tree compilation.

FluentValidation uses expression tree compilation in order to convert an expression into a delegate. For example, if you define a rule in FluentValidation by using RuleFor(x => x.Surname).NotNull() then FluentValidation will first parse the expression tree to extract the name of the property and then compile the expression into a delegate. This delegate can then be used in order to retrieve the value of the Surname property at runtime.

The Differences between Silverlight and Windows Phone article on MSDN simply states that “LambdaExpression.Compile is not supported in Windows Phone Developer Tools CTP Refresh.” This is because LambdaExpression uses Reflection.Emit internally in order to write IL, and Reflection.Emit is not supported under WP7.

The workaround was to write a simple extension method that can convert a MemberExpression (expressions that return the value of a property/field) into a delegate:

public static class ReflectionExtensions {
	public static TDelegate Compile<TDelegate>(this Expression<TDelegate> expression) {
		var compiledDelegate = CompilePropertyGetterExpression(expression, typeof(TDelegate));
		return (TDelegate)compiledDelegate;
	}
 
	static object CompilePropertyGetterExpression(LambdaExpression expression, Type delegateType) {
		var member = GetPropertyFromExpression(expression);
 
		if (member == null) {
			throw new NotSupportedException("FluentValidation for WP7 can only be used with expressions that reference public properties, eg x => x.SomeProperty");
		}
 
		var compiledDelegate = Delegate.CreateDelegate(delegateType, member.GetGetMethod());
		return compiledDelegate;
	}
 
	static PropertyInfo GetPropertyFromExpression(LambdaExpression expression) {
		var memberExp = UnwrapUnary(expression.Body);
 
		if (memberExp == null) {
			return null;
		}
 
		return memberExp.Member as PropertyInfo;
	}
 
	private static MemberExpression UnwrapUnary(Expression toUnwrap) {
		if (toUnwrap is UnaryExpression) {
			return ((UnaryExpression)toUnwrap).Operand as MemberExpression;
		}
 
		return toUnwrap as MemberExpression;
	}
}

This works by extracting the PropertyInfo from the MemberExpression’s Member property and then using Delegate.CreateDelegate to create a delegate from the property’s getter. The extension method can be used like the native implementation of Expression.Compile:

var person = new Person { Name = "Jeremy" };
 
Expression<Func<Person, string>> expression = x => x.Name;
var getter = expression.Compile();
 
var name = getter(person);
 
// Prints 'Jeremy'
Console.WriteLine(name);

Although the .NET framework’s native Expression.Compile does a lot more than this, I don’t really need the additional functionality for FluentValidation, so this solution works quite nicely.

Written on September 18, 2010