Func<> assign a value to the result

c# expression-trees lambda

Question

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 the 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.

Accepted Answer

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);

Popular Answer

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



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why