I needed some quiet time to finish this article so I took some vacations here (Mauritius Island)

Mauritius Island 

Expressions are used to evaluate something. We usually use them in the right side of an affectation or at any place where a value is expected. It can be composed with many other values, with computations or function calls.

When using objects we often retrieve values accessing properties or sub properties, defining property paths. This is what I will work on in this post.

Linq brought the Select method that we all know (one of my favorites).

We often use it to project from an entity to a new expression and many times we just use a property path.

customers.Select(c => c.Company.Address.Country);

Those of you who are familiar to Xaml are very used to property paths in binding expressions:

<TextBlock Text=”{Binding Path=Company.Address.Country}” />

Even if there are some differences, we could easily compare those two features.
One of the difference is WPF and Silverlight binding expressions can be “TwoWay”. This means that the property path expression can be used to both read or write the property value.

In C#, the selector is just pure code, so of course it compiles the natural access to the property (read only). Let’s think about how to make it possible to have a write access…

It’s not very difficult. If the expression only allows a sequence of chained properties, we just need to get the last one (Country in my example). Evaluating the rest of the expression (Company.Address) gives us the instance where we can get or set the last property value from.

To achieve this we need to be able to analyze the code which is not possible if it’s directly compiled into IL. The lambda syntax allows to use the same code to generate an expression instead of IL. Then we get an expression tree representing our property path, so we can analyze and understand it.

Let’s first try to do this in C# 3. Let’s imagine the final code we would like to have.

namespace CSharpRWSelector
{
    class Program
    {
        static void Main(string[] args)
        {
            var ps = PropertySelector<Customer>.Create(c => c.Address.Country);
 
            var cust = new Customer();
            cust.Address.Country = "FRANCE";
 
            Console.WriteLine(ps.GetValue(cust));
 
            ps.SetValue(cust, "FRANCE !");
 
            Console.WriteLine(cust.Address.Country);
        }
    }
 
    public class Customer
    {
        public Customer()
        {
            Address = new Address();
        }
        public string ID { get; set; }
        public Address Address { get; set; }
    }
    public class Address
    {
        public string Country { get; set; }
    }
}
 

Let’s imagine a PropertySelector class with a Create() method having the same prototype as the Linq Select().

public static PropertySelector<T, R> Create<R>(Expression<Func<T, R>> source)
{
 
}

You can notice that the Func<T, R> is surrounded with the Expression<T> class.
The use is exactly the same but we will get an Lambda expression instead of just a delegate reference.

First of all, getting a selector for reading is easy. We just need to compile the expression (source.Compile()) and we retrieve the right selector (Func<T,R>).

All the following is to get a way to write to the property.

Now let’s try to analyze this expression to retrieve the instance just before the last property of our property path.

We will have to implement a custom expression visitor. (see MSDN reference here)

I will quickly comment this part, but all the code is provided at the end of this post.

The expression visitor is massively recursive and is walking along all the expression tree.

We are only looking for properties (ie MemberAccess) and our goal is to catch the last one’s parent ! What I am mainly doing here is finding it and then wait for the next call to get the parent. You can notice that the properties of the path are discovered from right to left (last to first).

protected override Expression VisitMemberAccess(MemberExpression m)
{

if ((m.Member.MemberType == System.Reflection.MemberTypes.Property) &&
(!passed))

    {
        var lambda = Expression.Lambda(m.Expression, source.Parameters.ToArray());
        instanceSelector = lambda.Compile();
        propertyName = m.Member.Name;
        passed = true;
    }
    return base.VisitMemberAccess(m);
}

Once we get the parent (Address) we keep this reduced lamba expression (without the last property), we compile it and then we get a selector on the parent.

We can now implement the SetValue() method, using the selector to retrieve the parent instance given the source. Then, using reflection, we can retrieve the PropertyInfo and call the SetValue().

public void SetValue(T source, R value)
{
    var parent = instanceSelector.DynamicInvoke(source);
    var prop = parent.GetType().GetProperty(propertyName);
    prop.SetValue(parent, value, null);
}

As I said previously, the GetValue() is easy to implement. We just need to call the initial selector.

public R GetValue(T source)
{
    return selector(source);
}

I will also add some security code to be sure that only property paths are allowed.

code like c => c.SomeMethod().Property; must be rejected.

The expression visitor Visit() method is called for each node whatever its type. So it’s the perfect place to only accept property paths.

protected override Expression Visit(Expression exp)
{
    if ((exp.NodeType != ExpressionType.Parameter) &&
        (exp.NodeType != ExpressionType.Lambda) &&
        ((exp.NodeType != ExpressionType.MemberAccess) 
          && ((exp as MemberExpression).Member.MemberType 
          == System.Reflection.MemberTypes.Property)))
        throw new ArgumentException("Only Properties are allowed with PropertyPath");
    return base.Visit(exp);
}

Unfortunately, we have no way to check this at compile time.

Last but not least, let’s add an interesting improvement using C# 4.

In this first sample, you can notice that the GetValue is efficient because it’s a real ‘compiled’ selector but the SetValue is using reflection.

As explained in this very interesting post, C# 4 has new lambda expression features. Actually, not in the C# language itself but in the lambda expression APIs.

Affectation of a value was impossible to be described in a C# 3 lambda expression and it’s still not in C# 4, but we can build this expression tree bye code as the Expression.Assign() method now exists.

So now the goal is still to provide a Write access to my selector.

The visitor is now more complex as we want to make a real transformation of the tree.

From a selector Func<T, R> we want to infer an Action<T, R>.

The following code is very symbolic as it does not compiles but it gives a good idea of what we will try to generate:

From the analysis of

Func<Customer, string> f = c => c.Address.Country;

We will generate

Action<Customer, string> a = (cust, country) => cust.Address.Country = country;

Let’s modify the visitor:

protected override Expression VisitMemberAccess(MemberExpression m)
{
    var result = base.VisitMemberAccess(m);
 
    currentNode = Expression.MakeMemberAccess(currentNode, m.Member);
 
    return result;
}

In this first step, I am building a parallel expression tree copying the property path definition, excepted the lambda root.

We now need to build our Action<T, R>.

public PropertySelector<T, R> Compile(Expression<Func<T, R>> source)
{
    this.source = source;
 
    parameters = new List<ParameterExpression>();
 
    Visit(source);
 
    var valueParameter = Expression.Parameter(typeof(R), "value");
    parameters.Add(valueParameter);
    currentNode = Expression.Assign(currentNode, valueParameter);
    var setter = Expression.Lambda(typeof(Action<T, R>), currentNode, parameters);
 
    var result = new PropertySelector<T, R>() { 
        selector = source.Compile(), setter = (Action<T, R>)setter.Compile() };
 
    return result;
}

After running the visitor (Visit() method), I am retrieving the property path from currentNode and I am building the affectation with Expression.Assign().

Compared to the Func<T,R>, I also need to add a new R parameter which is the value to affect. (see parameters.Add(valueParameter); ).

Finally, a lambda expression groups all this stuff to create the Action<T,R>.

We can compile it and get the corresponding delegate (setter) which is real code instead of the reflection we’ve used in the C# 3 version.

We now just need to call it from the SetValue() method.

public void SetValue(T source, R value)
{
    setter(source, value);
    //var parent = instanceSelector.DynamicInvoke(source);
    //var prop = parent.GetType().GetProperty(propertyName);
    //prop.SetValue(parent, value, null);
}

The main application remains the same and we of course have the same result but we know use a dynamic solution by compiling code thanks to new C#4 expression tree features !

You can find the two relative solutions here for C# 3/VS2008 and C# 4/VS2010.

Mitsu