Background:

While writing the update post in my Data Service Provider series I ended up writing this block of reflection code to copy properties values from one object to another:

foreach (var prop in resourceType 
         .Properties 
         .Where(p => (p.Kind & ResourcePropertyKind.Key) 
                         != ResourcePropertyKind.Key))
{  
    var clrProp = clrType
           .GetProperties()
           .Single(p => p.Name == prop.Name); 
    var defaultPropValue = clrProp
           .GetGetMethod()
           .Invoke(resetTemplate, new object[] { }); 
    clrProp 
      .GetSetMethod()
      .Invoke(resource, new object[] { defaultPropValue }); 
}

Problem:

This code has at least two major problems.

  1. It is finding properties and methods via reflection in a loop
  2. It is invoking those methods using reflection in a loop.

We could address (1) by storing all the property get / set methods in some cacheable data-structure.

But fixing (2) is a little more tricky, to make this code truly generic you need to use something like lightweight code-gen, or worse.

Solution:

Thankfully .NET 4.0 adds statement expressions. Which means you can create expressions that describe multi-line statements now, and yes those statements can do things like assignments.

Picture Borat saying ‘Nice…’

A quick search of the interweb revealed this excellent post on statement expressions by Bart, and that was enough to get me – and I hope you – to get excited.

Step 1 – Getting familiar with the API

Armed with my new found enthusiasm I decided to dip my toes in the water with something simple, namely trying to convert this into an expression:

Func<int> func = () => {
    int n; 
    n=2;
    return n;
};

It would be awesome if you could just do this:

Expression<Func<int>> expr = () => {
    int n; 
    n = 2;
    return n;
};

But unfortunately C# doesn’t support this today, instead you have to manually construct the expression, like this:

var n = Expression.Variable(typeof(int));
var expr = Expression.Lambda<Func<int>>
(
    Expression.Block(
        // int n;
        new[] { n },
        // n = 2;
        Expression.Assign(
            n,
            Expression.Constant(2)
        ),
        // return n;

        n
    )
);

Pretty easy huh.

Step 2 – Proving we can assign to a property

Now we’ve got a feel for the API, it’s time to start applying it to our problem.

What we need is a function that will modify an Object (in this case a product) by resetting one or more of its properties, like this:

Action<Product> baseReset = (Product p) => { p.Name = null; };

This code creates an equivalent action using the new expression APIs:

var parameter = Expression.Parameter(typeof(Product));   
var resetExpr = Expression.Lambda<Action<Product>>(
        Expression.Block(
            Expression.Assign(
                Expression.Property(parameter,"Name"),
                Expression.Constant(null, typeof(string))
            )
        ),
        parameter
    );
var reset = resetExpr.Compile();
var product = new Product { ID = 1, Name = "Foo" };
reset(product);

And sure enough after reset(product) is called the product Name is null.

Step 3 – Assigning to all non key properties

Now all we need to do is create a function that when given a particular CLR type will create an expression to reset all the non-key properties.

Actually collecting the list of properties and their intended values, isn’t interesting for this discussion, so lets imagine we’ve already got that information in a dictionary, like this:

var properties = new Dictionary<PropertyInfo, object>();
var productProperties = typeof(Product).GetProperties();

var nameProp = productProperties.Single(p => p.Name == "Name");
var costProp = productProperties.Single(p => p.Name == "Cost");
properties.Add(nameProp, null);
properties.Add(costProp, 0.0M);

Given this data-structure our job is to create an expression that has the same affect as this action:

Action<Product> baseReset = (Product p) => {
       p.Name = null; 
       p.Cost = 0.0M;
};

First we need to create all the assignment expressions:

var parameter = Expression.Parameter(typeof(Product));
List<Expression> assignments = new List<Expression>();
foreach (var property in properties.Keys)
{
    assignments.Add(Expression.Assign(
        Expression.Property(parameter, property.Name),
        Expression.Convert(
            Expression.Constant(
                properties[property],
                property.PropertyType
            )
        )
    );
}
  

Next we feed the assignment expressions into a block inside a lambda, compile the whole thing and test out our nifty new function:

var resetExpr = Expression.Lambda<Action<Product>>(
    Expression.Block(
        assignments.ToArray()
    ),
    parameter
);
var reset = resetExpr.Compile();
var product = new Product { ID = 1, Name = "Foo", Cost = 34.5M };
reset(product);
Debug.Assert(product.Name == null);
Debug.Assert(product.Cost == 0.0M);

As expected this works like a charm.

To solve the problem I had in my Update Post, we’d need a dictionary keyed on type, that we can used to store the reset action for a particular type. Then if a type’s reset action it isn’t found we just create it…

And our performance problem should be a thing of the past :)