Question

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;
}
Was it helpful?

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>;

OTHER TIPS

You should add the cast into your expression (using Expression.Convert):

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(typeof(object), "param");
     ParameterExpression parami = Expression.Parameter(typeof(TProp), "newvalue");
     MethodCallExpression methodCallSetterOfProperty = 
         Expression.Call(Expression.Convert(paramo, type), setterMethodInfo, parami);
     var setPropertyValueExp = 
         Expression.Lambda<Action<object, TProp>>(methodCallSetterOfProperty, paramo, parami);

     var setterFunc = setPropertyValueExp.Compile();
     return setterFunc;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top