What I am trying to do seems simple, but I can't find a way. Let's suppose I have a method with this signature:
public void Foo<T,K>(Expression<Func<T,K>> binding, T item, K value)
What I want to do inside my method is: applying the Func to item, getting t开发者_运维百科he property of type K to which the binding expression points to, and assign "value" to it.
If the binding expression is something like:
c => c.Property
Where "c" is "T", and "Property" is "K", I can use some reflection easily and set the value using FieldInfo. The following code works:
(((binding as LambdaExpression).Body as MemberExpression).Member as FieldInfo).SetValue(item, value);
But the expression could be something like this:
c => c.SubClass.Property
or
c => c.SubClass1.SubClass2.SubClassN.Property
In this case the reflection code doesn't work, as "Property" doesn't belong directly to T, but it's still a valid lambda expression for the signature of the method.
I know that if I compile the Func and run it on my item of type T I get the property, but it's like a "copy" of it, and not a reference of it, so even if I assign the value to it, the property on the original item doesn't get changed.
If anyone has a clean solution to this, or just point me to something that can grant me a better knowledge of Expression Trees, you're very welcome.
It sounds like you don't really want a 'K' from a T, but instead you want to assign a K to a K that T knows about, right?
public void Foo<T,K>(Action<T,K> binding, T item, K value)
{
binding(item, value);
}
Seems more correct because binding is a delegate that can take a T and tell T to do the right thing with a K, right? Call it like this?
Foo<T,K>((t, k) => t.SubClass.Property = k, aT, aK);
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);
}
Usage:
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");
精彩评论