Specifying properties using Lambda expression trees instead of Reflection

For my TranslationTester project I need users to be able to specify properties on classes so that they can specify that one property maps to another, and to indicate which property they are mapping (or even excluding).

Up until now I’ve only been able to achieve this using strings that match the property names. This is bad because a) it’s difficult to use, and b) it doesn’t support refactoring very well – (although the tests give helpful exceptions when a property has been renamed it would still need to be manually corrected)

Whilst attending DDD7 I saw a demo on LINQ by Jon Skeet and saw a type of Lambda expression I’d not really seen before that was being used to specify a Key on  class. This got me to thinking that this is basically what I want to do. Looking into it I found a few other resources explaining how to do this.

Here’s what I came up with:

target.AddMapping(f=>f.Property1,t=>t.Property1);

which is achieved by:

public SimpleMapping<TFrom, TTo> AddMapping<TProp>(
  Expression<Func<TFrom, TProp>> fromProp,
  Expression<Func<TTo, TProp>> toProp)
{
  var fromName = fromProp.ToPropertyName();
  var toName = toProp.ToPropertyName();
  return AddMapping(fromName, toName);
}  

...

public static class ExpressionExtensions
{   
    public static string ToPropertyName<TFrom, TProp>(this Expression<Func<TFrom, TProp>> propertyExpression)
    {
      var lambda = ToLambda(propertyExpression);
      var prop = lambda.Body as MemberExpression;    
      if (prop != null)
      {
        var info = prop.Member as PropertyInfo;
        if (info != null)
        {
          return info.Name;
        }
      }      
      throw new ArgumentException();
    }    

    private static LambdaExpression ToLambda(Expression expression)
    {
      var lambda = expression as LambdaExpression;
      if (lambda == null)
      {
        throw new ArgumentException();
      }  
      var convertLambda = lambda.Body as UnaryExpression;
      if (convertLambda != null
          && convertLambda.NodeType == ExpressionType.Convert)
      {
        lambda = Expression.Lambda(convertLambda.Operand, lambda.Parameters.ToArray());
      }  
      return lambda;
    }
}

Note: Some of this is borrowed/inspired very heavily from Moq, particularly the conversion of lambda convert expressions.

One of the nifty things about it is that the syntax of the two Expressions enforces a lot of the requirements on the property types. By using TProp the properties that are referenced in the expressions must be of the same (or common base) type.

I’ve been using the new way of referring to properties and I must say I’m really happy with it!

Advertisements

About Alex McMahon

I am a software developer, interested in .net, agile, alt.net. I've previously specialised with .net 3.0 technologies like WCF, whereas now I am trying to specialise in agile development and best practice and patterns. I am obsessed with looking at the latest technologies, tools, and methods, and trying them out. I am currently employed by Rockwell Collins in the UK.
This entry was posted in .net, development, techniques, TranslationTester. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s