FUNC<>为结果赋值

时间:2011-01-14 17:22:47

标签: c# lambda expression-trees

我想做的事情似乎很简单,但我找不到办法。假设我有一个带有此签名的方法:

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类型的项目上运行它获取属性,但它就像它的“副本”,而不是它的引用,所以即使我将值赋给它,原始项目的属性不会改变。

如果有人对此有一个干净的解决方案,或者只是指出一些可以让我更好地了解表达树的东西,那么非常受欢迎。

2 个答案:

答案 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");