1

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?

MarkusParker
  • 1,264
  • 2
  • 17
  • 35
  • Is there a requirement to build a lambda that sets the value? If not, can you just use the reflection to get the member and set its value after you know the name of the member involved? – Wiktor Zychla Aug 28 '19 at 13:20
  • @WiktorZychla: The setter may be used frequently, that is why I prefer an expression-tree based solution to a reflection based one. – MarkusParker Aug 28 '19 at 13:23
  • MarkusParker: Have you looked at this question? https://stackoverflow.com/questions/4085798/creating-an-performant-open-delegate-for-an-property-setter-or-getter – jgauffin Aug 28 '19 at 13:35
  • @jgauffin: As far as I understand, that question deals with properties, which I can handle. I got a problem with fields. – MarkusParker Aug 28 '19 at 13:49

1 Answers1

2

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.

Krzysztof
  • 15,900
  • 2
  • 46
  • 76