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.
Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y . You can compile and run code represented by expression trees.
Expression trees allow you to build code dynamically at runtime instead of statically typing it in the IDE and using a compiler. They are well explained in the documentation.
Expression Trees was first introduced in C# 3.0 (Visual Studio 2008), where they were mainly used by LINQ providers. Expression trees represent code in a tree-like format, where each node is an expression (for example, a method call or a binary operation such as x < y).
An expression tree is a representation of expressions arranged in a tree-like data structure. In other words, it is a tree with leaves as operands of the expression and nodes contain the operators. Similar to other data structures, data interaction is also possible in an expression tree.
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();
}
You need to return MethodInfo
instead of Action<double>
, also the Invoke(object obj, object[] params)
takes the original object and the parameters :
static MethodInfo GetSetterForX(Expression<Func<double>> expression)
{
var body = expression.Body;
var operand = body as MemberExpression;
var propertyInfo = (PropertyInfo)(operand.Member);
var setter = propertyInfo.GetSetMethod(true);
return setter;
}
public static void Main()
{
var testObject = new TestObject();
var setter = GetSetterForX(() => testObject.X);
setter.Invoke(testObject, new object[]{5});
Debug.Assert(testObject.X == 5);
}
Fiddle : https://dotnetfiddle.net/CHJGbk
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