如何在c#中转换表达式树lambda?

时间:2014-01-15 14:23:54

标签: c# casting lambda expression-trees

我有一个表达式树表达式

var lambdaExpr 

编译时会生成

Action<Type,int>

但是我想包装它并生成一个表达式,在编译时会生成

Action<object, int>

我需要强制对动作的第一个参数强制转换,然后在将它传递给原始lambda之前将其转换为

object --- cast ---> Type

如果无法进行强制转换,那么在执行时显然会通过运行时异常。

如何将原始表达式树表达式包装到新表达式中?

具体来说,我需要在下面指出的地方添加一些额外的代码,以使类型正确。

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

2 个答案:

答案 0 :(得分:3)

你需要拿走你的Action<Type,int> lambda并生成一个Action<object,int> lambda来执行演员并调用它:

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

答案 1 :(得分:1)

您应该将演员表添加到表达式中(使用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;
}