我想做的事情似乎很简单,但我找不到办法。假设我有一个带有此签名的方法:
public void Foo<T,K>(Expression<Func<T,K>> binding, T item, K value)
我想在我的方法中做的是:将Func应用于item,获取绑定表达式指向的K类型的属性,并为其指定“value”。
如果绑定表达式类似于:
c => c.Property
“c”为“T”,“Property”为“K”,我可以轻松使用一些反射并使用FieldInfo设置值。以下代码有效:
(((binding as LambdaExpression).Body as MemberExpression).Member as FieldInfo).SetValue(item, value);
但表达式可能是这样的:
c => c.SubClass.Property
或
c => c.SubClass1.SubClass2.SubClassN.Property
在这种情况下,反射代码不起作用,因为“Property”不直接属于T,但它仍然是方法签名的有效lambda表达式。
我知道如果我编译Func并在TI类型的项目上运行它获取属性,但它就像它的“副本”,而不是它的引用,所以即使我将值赋给它,原始项目的属性不会改变。
如果有人对此有一个干净的解决方案,或者只是指出一些可以让我更好地了解表达树的东西,那么非常受欢迎。
答案 0 :(得分:3)
听起来你真的不想从T中得到'K',而是想要给K知道的K分配K,对吗?
public void Foo<T,K>(Action<T,K> binding, T item, K value)
{
binding(item, value);
}
似乎更正确,因为绑定是一个委托,它可以取一个T并告诉T用K做正确的事,对吧?这样称呼它?
Foo<T,K>((t, k) => t.SubClass.Property = k, aT, aK);
答案 1 :(得分:2)
static void AssignValue<TSource, TResult>(Expression<Func<TSource, TResult>> expression, TSource source, TResult result)
{
var paramExp = expression.Parameters.Single();
var assignExp = Expression.Assign(expression.Body, Expression.Constant(result));
var lambdaExp = Expression.Lambda(assignExp, paramExp);
lambdaExp.Compile().DynamicInvoke(source);
}
用法:
class Product
{
public int ID { get; set; }
public string Name { get; set; }
}
var product = new Product { ID = 99, Name = "haha" };
AssignValue<Product, string>(p => p.Name, product, "changed");