Func <> asignar un valor al resultado

c# expression-trees lambda

Pregunta

Lo que estoy tratando de hacer parece simple, pero no puedo encontrar una manera. Supongamos que tengo un método con esta firma:

public void Foo<T,K>(Expression<Func<T,K>> binding, T item, K value)

Lo que quiero hacer dentro de mi método es: aplicar el Func al elemento, obtener la propiedad de tipo K a la que apunta la expresión de enlace y asignarle "valor".

Si la expresión de enlace es algo como:

c => c.Property

Donde "c" es "T", y "Propiedad" es "K", puedo usar un poco de reflexión y establecer el valor utilizando FieldInfo. El siguiente código funciona:

(((binding as LambdaExpression).Body as MemberExpression).Member as FieldInfo).SetValue(item, value);

Pero la expresión podría ser algo como esto:

c => c.SubClass.Property

o

c => c.SubClass1.SubClass2.SubClassN.Property

En este caso, el código de reflexión no funciona, ya que "Propiedad" no pertenece directamente a T, pero sigue siendo una expresión lambda válida para la firma del método.

Sé que si compilo el Func y lo ejecuto en mi artículo de tipo TI, obtengo la propiedad, pero es como una "copia" de ella, y no una referencia de la misma, por lo que incluso si le asigno el valor, la propiedad en el artículo original no se cambia

Si alguien tiene una solución limpia para esto, o simplemente me apunta a algo que me permita obtener un mejor conocimiento de Expression Trees, de nada.

Respuesta aceptada

Parece que realmente no quieres una 'K' de una T, sino que quieres asignar una K a una K que T conoce, ¿verdad?

public void Foo<T,K>(Action<T,K> binding, T item, K value)
{
    binding(item, value);
}

Parece más correcto porque el enlace es un delegado que puede tomar una T y decirle a T que haga lo correcto con una K, ¿verdad? Llámalo así?

Foo<T,K>((t, k) => t.SubClass.Property = k, aT, aK);

Respuesta popular

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

Uso:

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


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow