I try to modify this answer by making the class instance a parameter. The main idea is to create a setter for a class member no matter if it is a field or a property. I was successful with properties but got stuck with fields. This is the relevant part of the original code:
public static Action<T> ToSetter<T>(Expression<Func<T>> expr) {
var memberExpression = (MemberExpression)expr.Body;
var instanceExpression = memberExpression.Expression;
var parameter = Expression.Parameter(typeof(T));
// assuming memberExpression.Member is FieldInfo;
return Expression.Lambda<Action<T>>(Expression.Assign(memberExpression, parameter), parameter).Compile();
}
Application:
var setter= ToSetter<string>(() => myClient.WorkPhone);
setter("12345");
This is what I want to have:
public static Action<O,T> ToSetter<T,O>(Expression<Func<O,T>> expr) where O : class {
var memberExpression = (MemberExpression)expr.Body;
var instance = Expression.Parameter(typeof(O));
var parameter = Expression.Parameter(typeof(T));
// the following throws an InvalidOperationException exception:
return Expression.Lambda<Action<O,T>>(
Expression.Assign(memberExpression, parameter), parameter).Compile();
}
Application:
var setter= ToSetter<Client,string>(c=> c.WorkPhone);
setter(myClient, "12345");
How do I have to modify Expression.Lambda<Action<O,T>>(Expression.Assign(memberExpression, parameter),instance, parameter).Compile()
to consider the instance of class O
?
Try this:
// Example usage: ToSetter<MyEntity, string>(c => c.FirstName)
public static Action<TEntity, TResult> ToSetter<TEntity, TResult>(Expression<Func<TEntity, TResult>> expr)
{
// This will be `c.FirstName`
var memberExpression = (MemberExpression)expr.Body;
// This will be `c`
var instanceParameter = (ParameterExpression)memberExpression.Expression;
// New parameter for passing value named `value`
var valueParameter = Expression.Parameter(typeof(TResult), "value");
// Construct `(c, value) => c.FirstName = value`
return Expression.Lambda<Action<TEntity, TResult>>(
Expression.Assign(memberExpression, valueParameter), // c.FirstName = value
instanceParameter, // c
valueParameter // value
).Compile();
}
What you have been missing is second parameter for Lambda
call. Also, memberExpression
has some parameter inside from original lambda, and it must be the same as in new lambda.