如何从表达式树中设置 属性 值?
How to set a property value from 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);
}
}
}
我可以获得 setter 但无法找到访问实例 (testObject) 的方法。有办法吗?
请注意,这是一个简化的示例。我将使用更复杂的表达式,其中包含许多 属性 引用,我希望能够(单独)设置所有这些引用。
更新
澄清一下。我想要返回一个 setter,它只需要一个双精度值,并且它分配给 testObject 的 X 属性。这应该是可能的,而无需在 setter 中显式传递对 testObject 的引用。
我可以做同样的事情来获得 getter 但不是 setter。这是 getter 代码:
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();
}
返回的 getter 始终在 testObject 实例上工作。不用再传入testObject了
您需要 return MethodInfo
而不是 Action<double>
,Invoke(object obj, object[] params)
也采用原始对象和参数:
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
只要输入的lambda表达式表示成员访问器,就可以使用Expression.Assign传递输入的lambda表达式主体和表示值的参数,例如
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();
}
我想设置表达式树中引用的 属性 值。
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);
}
}
}
我可以获得 setter 但无法找到访问实例 (testObject) 的方法。有办法吗?
请注意,这是一个简化的示例。我将使用更复杂的表达式,其中包含许多 属性 引用,我希望能够(单独)设置所有这些引用。
更新
澄清一下。我想要返回一个 setter,它只需要一个双精度值,并且它分配给 testObject 的 X 属性。这应该是可能的,而无需在 setter 中显式传递对 testObject 的引用。 我可以做同样的事情来获得 getter 但不是 setter。这是 getter 代码:
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();
}
返回的 getter 始终在 testObject 实例上工作。不用再传入testObject了
您需要 return MethodInfo
而不是 Action<double>
,Invoke(object obj, object[] params)
也采用原始对象和参数:
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
只要输入的lambda表达式表示成员访问器,就可以使用Expression.Assign传递输入的lambda表达式主体和表示值的参数,例如
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();
}