tags:

views:

177

answers:

2

It is relatively easy to create a lambda function that will return the value of a property from an object, even including deep properties...

Func<Category, string> getCategoryName = new Func<Category, string>(c => c.Name);

and this can be called as follows...

string categoryName = getCategoryName(this.category);

But, given only the resulting function above (or the expression originally used to create the function), can anybody provide an easy way to create the opposing action...

Action<Category, string> setCategoryName = new Action<Category, string>((c, s) => c.Name = s);

...that will enable the same property value to be set as follows?

setCategoryName(this.category, "");

Note that I am looking for a way to create the action programatically from the function or expression - I hope that I have shown that I already know how to create it manually.

I am open to answers that work in both .net 3.5 and 4.0.

Thanks.

UPDATE:

Perhaps I am not being clear in my question, so let me try and demonstrate more clearly what I am trying to do.

I have the following method (that I have created for the purposes of this question)...

void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression) {

    Func<TObject, TValue> getValue = expression.Compile();
    TValue stuff = getValue(obj);

    Expression<Action<TObject, TValue>> assignmentExpression = (o, v) => Expression<TObject>.Assign(expression, Expression.Constant(v, typeof(TValue)));
    Action<TObject, TValue> setValue = assignmentExpression.Compile();

    setValue(obj, stuff);

}

What I am looking for is how do I create the "assignmentExpression" within the code so that I can compile it into setValue? I figure it is related to Expression.Assign, but I simply cannot work out the correct combination of parameters to complete the code.

The eventual result is to be able to call

Category category = *<get object from somewhere>*;
this.DoLambdaStuff(category, c => c.Name);

and this in turn will create a getter and a setter for the "Name" property of the Category object.

The version above compiles, but when I call setValue() it results in an ArgumentException with "Expression must be writeable".

Thanks again.

+1  A: 

This should be possible using expression trees, which can be created from lambda expressions, modified, and then compiled into a delegate.

Stephen Cleary
This is the sort of thing I was looking for, I was just hoping for an example!
Martin Robins
+2  A: 

Ok, the code I am looking for goes something like this...

ParameterExpression objectParameterExpression = Expression.Parameter(typeof(TObject)), valueParameterExpression = Expression.Parameter(typeof(TValue));
            Expression<Action<TObject, TValue>> setValueExpression = Expression.Lambda<Action<TObject, TValue>>(
                Expression.Block(
                    Expression.Assign(Expression.Property(objectParameterExpression, ((MemberExpression)expression.Body).Member.Name), valueParameterExpression)
                ), objectParameterExpression, valueParameterExpression
            );
            Action<TObject, TValue> setValue = setValueExpression.Compile();

This code works, but only for shallow properties (that is, properties of the immediate object) but does not work for deep properties - although the getter function can work for deep properties. It would be interesting to know if anybody can help me modify this to work with deep properties but I will raise this as a seperate question.

Martin Robins
This code only works in .NET 4 as it requires the improved support for expression trees introduced in in .NET 4.
Martin Liversage