1

Consider a property expression like t => t.MyProperty where t is of type MyClass. How can I use this property expression inside a new expression where I perform a method call?

Pure C#:

class MyClass
{
    public string MyProperty { get; set; }
}

static void Foo(string foo)
{   
}

LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
{
    return expr;
}

var myClass = new MyClass();
Foo(myClass.MyProperty);

Now with expressions...?

var expr = GetExpression(m => m.MyProperty);
var mi = typeof(Program).GetMethod(nameof(Program.Foo),
    BindingFlags.Public | BindingFlags.Static);

var myClass = new MyClass();
// Now what??
// var call = Expression.Call(mi, ???expr??);
// var invoke = Expression.Invoke(call, fooParameter);

I want to use the result of expr and use that in the call to Foo. I know I can do this in two steps, where I call expr.Compile().DynamicInvoke(myClass) to get the value, but that is not what I'm asking for here.

I want to build an expression that takes a property getter expression and then performs a call to Foo(result of expression). I cannot figure out how to use the expression as a parameter to the method call.

6
  • It's not clear at all what you are trying to achieve. Method Foo takes a string; your Expression produces an object. What expression would you like to use as a parameter to what method call? Commented Apr 7, 2017 at 14:57
  • 1
    if I understand it, you should just be able to use Expression.Call(mi, Expression.Invoke( ... )) ? Commented Apr 7, 2017 at 14:59
  • That's part of the challenge. Need for conversion, maybe. It is clear what I'm trying to achieve. For a given MyClass object M, I want to call Foo(M.MyProperty). The input is an expression as produced by GetExpression method above. Commented Apr 7, 2017 at 14:59
  • gotcha; give me a sec... Commented Apr 7, 2017 at 15:00
  • @l33t Foo takes a string, while Expression produces an object. Do you want a simple cast in between, because you know that the object is actually a string? Commented Apr 7, 2017 at 15:03

1 Answer 1

3

There's two ways of doing this, depending on the complexity. In this case, we can re-use the parameter from the inner expression - bubbling it outwards; we do this by discarding our old lambda, just using the .Body and .Parameters. For example:

var call = Expression.Lambda<Action<MyClass>>(
    Expression.Call(mi, expr.Body), expr.Parameters);

var myClass = new MyClass { MyProperty = "yay!" };
call.Compile().Invoke(myClass);

The other way is to use Invoke on the inner lambda:

var outerParameter = Expression.Parameter(typeof(MyClass));
var typed = Expression.Convert(Expression.Invoke(expr, outerParameter), typeof(string));
var call = Expression.Lambda<Action<MyClass>>(Expression.Call(mi, typed), outerParameter);

The second form (Invoke) is useful when you can't conveniently control the parameters in the two places - or where, for example, you have multiple inner expressions with different parameter instances.

Sign up to request clarification or add additional context in comments.

3 Comments

Wow. Saved my day. Thanks!
Second approach is actually very useful in my case. Thanks.
@l33t there's actually a third option if you want: use a custom ExpressionVisitor to replace all of one expression with another expression - for example, to substitute an inner parameter with an outer parameter, but works for any expression. Can provide examples if you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.