Search code examples
c#castinglambdaexpression-trees

How to cast an expression tree lambda in c#?


I have an expression tree expression

var lambdaExpr 

which when compiled will generate

Action<Type,int>

However I would like to wrap this and generate an expression which when compiled will generate

Action<object, int>

and I will need to force a cast on the first argument to the action to convert it before passing it to the original lambda

object --- cast ---> Type

which when executed will obviously through a runtime exception if the cast is not possible.

How do I wrap the original expression tree expression into the new one?

Specifically I need to add some extra code where indicated below to get the types correct.

private static Action<object, TProp> GenerateSetter<TProp>(Type type, string propertyName )
{
     var property = type.GetProperty
         (propertyName, BindingFlags.Public 
         | BindingFlags.Instance
         | BindingFlags.NonPublic);
     MethodInfo setterMethodInfo = property.SetMethod;
     ParameterExpression paramo = Expression.Parameter(type, "param");
     ParameterExpression parami = Expression.Parameter(typeof(TProp), "newvalue");
     MethodCallExpression methodCallSetterOfProperty = 
         Expression.Call(paramo, setterMethodInfo, parami);
     Expression setPropertyValueExp = 
         Expression.Lambda(methodCallSetterOfProperty, paramo, parami);

     // This line below fails because setPropertyValueExp is an
     //  Action with first argument
     // being the type passed in at runtime. I need to wrap it with a lambda that 
     // casts the object to the correct type.

     var setPropertyValueLambda = 
         ( Expression<Action<object, TProp>> ) setPropertyValueExp;
     var setterFunc = setPropertyValueLambda.Compile();
     return setterFunc;
}

Solution

  • You need to take your Action<Type,int> lambda and generate a Action<object,int> lambda that does the cast and calls it:

     var p=Expression.Parameter(typeof(object));
     var conversion=Expression.Convert(p,type);
     var call=Expression.Invoke(setPropertyValueExp,conversion);
     var lambda=Expression.Lambda(call,p);
     return lambda.Compile() as Action<object,int>;