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.
To convert an anonymous method to a lambda expressionMove to the anonymous method you want to convert. From the Refactor menu of the VisualAid choose To Lambda. Telerik® JustCode™ will replace the anonymous method with a lambda expression.
You can use a capture-default mode to indicate how to capture any outside variables referenced in the lambda body: [&] means all variables that you refer to are captured by reference, and [=] means they're captured by value.
void DoLambdaStuff<TObject, TValue>(TObject obj, Expression<Func<TObject, TValue>> expression) {
Func<TObject, TValue> getValue = expression.Compile();
TValue stuff = getValue(obj);
var p = Expression.Parameter(typeof(TValue), "v");
Expression<Action<TObject, TValue>> assignmentExpression =
Expression.Lambda<Action<TObject, TValue>>(Expression.Assign(expression.Body, p), expression.Parameters[0], p);
Action<TObject, TValue> setValue = assignmentExpression.Compile();
setValue(obj, stuff);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With