neManiac
neManiac

Reputation: 355

Can I dynamically create an expression representing a lambda which calls a method on the input parameter?

Let's say I have an object of a certain class A. Let's say I need an Expression which calls method M on class A. Is this even doable?

Basically, I need to programatically get this lambda a => a.M();

The trick is, I want to do this generically, i.e. I plan to use reflection to figure out that the method is called M and what parameters it wants.

I tried using Expression.Lambda(MethodCallExpression method, ParameterExpression params).

The issue there is that when I define the method call expression, I have to specify an instance (or leave it at null if it's a static method, which it isn't). I don't want this. I want whatever the parameter is passed into the lambda (a in my example) to be the instance.

Is this possible?

Upvotes: 4

Views: 912

Answers (1)

Renat
Renat

Reputation: 8992

Yes, it's possible to construct a linq expression at a runtime.

E.g. below is an example of constructing an expression of a method call which returns an object. This is really a dummy example as it's better to avoid object in favor of strict types.

static Expression<Func<T, object>> ComposeMethodCallExpressionAsFuncObject<T>(string methodName)
{
    MethodInfo mi = typeof(T).GetMethod(methodName, types: new Type[0])
        ?? throw new ArgumentException($"There is no '{methodName}' method in the '{typeof(T).Name}' with the empty arguments list!");

    var paramExpression = Expression.Parameter(typeof(T));
    var methodCallExpression = Expression.Call(paramExpression, mi);

    var result = Expression.Lambda<Func<T, object>>(methodCallExpression, paramExpression);
    return result; // (T obj) =>obj.methodName()
}

, and example of usage:

int foo = 9988;
var expression = ComposeMethodCallExpressionAsFuncObject<int>(nameof(int.ToString));
//expression: (int obj) => obj.ToString()
var result = expression.Compile()(foo);
Assert.AreEqual("9988", result);

Upvotes: 2

Related Questions