I would like to set the property value referenced in an expression tree.
using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp8
{
class TestObject
{
public double X { get; set; }
}
class Program
{
static Action<double> GetSetterForX(Expression<Func<double>> expression)
{
var body = expression.Body;
var operand = body as MemberExpression;
var propertyInfo = (PropertyInfo) (operand.Member);
var setter = propertyInfo.GetSetMethod(true);
// At this point I have the setter. But how do I get access to the testObject?
return null;
}
static void Main(string[] args)
{
var testObject = new TestObject();
var setter = GetSetterForX(() => testObject.X);
setter.Invoke(5);
Debug.Assert(testObject.X == 5);
}
}
}
I can get the setter but can not find a way to get access to the instance (testObject). Is there a way?
Note that this is a simplified example. I will use much more complex expressions with many property references inside and I would like to be able to set all of them (individually).
UPDATE
To clarify. I would like to have a setter returned which only takes a double and it assigns testObject's X property. This should be possible without the need to explicitly pass in the reference to testObject in the setter. I can do the same to get a getter but not for setter. Here is the getter code:
static Func<double> GetGetterForX(Expression<Func<double>> expression)
{
var body = expression.Body;
var operand = body as MemberExpression;
var result = new Func<double>(() => (double) GetValue(operand));
return result;
}
private static object GetValue(MemberExpression member)
{
var objectMember = Expression.Convert(member, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
return getter();
}
The getter returned is always working on the testObject instance. No need to pass in the testObject again.
As soon as the input lambda expression represents member accessor, you can use Expression.Assign passing the input lambda expression body and parameter representing the value, e.g.
static Action<double> GetSetterForX(Expression<Func<double>> expression)
{
var parameter = Expression.Parameter(typeof(double), "value");
var body = Expression.Assign(expression.Body, parameter);
var lambda = Expression.Lambda<Action<double>>(body, parameter);
return lambda.Compile();
}