Create an Action to "set" a property, when I am provided with the LINQ Expression for the "get"

c# expression-trees


I'd like to be able to generate a compiled expression to set a property, given the lambda expression that provides the "get" method for a property.

Here's what I'm looking for:

public Action<int> CreateSetter<T>(Expression<Func<T, int>> getter)
    // returns a compiled action using the details of the getter expression tree, or null
    // if the write property is not defined.

I'm still trying to understand the various types of Expression classes, so if you can point me in the right direction that would be great.

Accepted Answer

Using @Ani's answer as a starting point, you can use the following to generate a compiled expression.

public void CreateSetterFromGetter()
    Action<Person, int> ageSetter = InitializeSet((Person p) => p.Age);
    Action<Person, string> nameSetter = InitializeSet((Person p) => p.Name);

    Person p1 = new Person();
    ageSetter(p1, 29);
    nameSetter(p1, "John");

    Assert.IsTrue(p1.Name == "John");
    Assert.IsTrue(p1.Age == 29);

public class Person { public int Age { get; set; } public string Name { get; set; } }

public static Action<TContainer, TProperty> InitializeSet<TContainer, TProperty>(Expression<Func<TContainer, TProperty>> getter)
    PropertyInfo propertyInfo = (getter.Body as MemberExpression).Member as PropertyInfo;

    ParameterExpression instance = Expression.Parameter(typeof(TContainer), "instance");
    ParameterExpression parameter = Expression.Parameter(typeof(TProperty), "param");

    return Expression.Lambda<Action<TContainer, TProperty>>(
        Expression.Call(instance, propertyInfo.GetSetMethod(), parameter),
        new ParameterExpression[] { instance, parameter }).Compile();

You should cache the compiled expression to keep it handy for multiple uses.

Expert Answer

Pointers only I'm afraid (I'm not at a pc) - but;

  • the lambda's .Body will most likely be MemberExpression
  • do a safe cast (as etc) and access the .Member
  • since you belive this a property, this should be a PropertyInfo, so test/cast etc
  • from a PropertyInfo, call GetSetMethod() to get the corresponding MethodInfo
  • use Delegate.CreateDelegate to get that as a delegate (passing the action type)
  • finally, cast the Delegate returned onto the expected delegate type

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