从MethodInfo创建的表达式树中显式转换参数

时间:2016-03-24 00:14:18

标签: c# expression-trees

我有下面的方法,将(非静态)MethodInfo转换为已编译的表达式(Func),然后我可以调用它。

这很好用:我可以使用期望引用对象和值类型的方法来调用它。

但与原始方法不同,我可以调用一个参数期望double的方法并将其传递给int这个编译的表达式不支持它并抛出{{1} }}

如何修改它以支持在正常方法调用期间发生的相同类型的隐式转换?

加分问题:instanceExp应该使用InvalidCastException中的DeclaringType还是ReflectedType

MethodInfo

---编辑

工作解决方案是:

public Func<object, object[], object> Create(MethodInfo methodInfo)
{
    var methodParams = methodInfo.GetParameters();
    var arrayParameter = Expression.Parameter(typeof(object[]), "array");

    var arguments =
        methodParams.Select((p, i) => Expression.Convert(
            Expression.ArrayAccess(arrayParameter, Expression.Constant(i)), p.ParameterType))
            .Cast<Expression>()
            .ToList();

    var instanceParameter = Expression.Parameter(typeof(object), "controller");

    var instanceExp = Expression.Convert(instanceParameter, methodInfo.DeclaringType);
    var callExpression = Expression.Call(instanceExp, methodInfo, arguments);

    var bodyExpression = Expression.Convert(callExpression, typeof(object));

    return Expression.Lambda<Func<object, object[], object>>(
        bodyExpression, instanceParameter, arrayParameter)
        .Compile();
}

1 个答案:

答案 0 :(得分:4)

问题与这段C#代码相同:

object a = 123;
double b = (double)a; // InvalidCastException

原因是aobject,因此为了使其成为double,演员必须解开它,然后将int转换为{{ 1}}。该语言允许演员只做一件事 - 它将展开或转换,但不是两者。您需要告诉编译器如何明确地执行此操作,方法是告诉它double内包含int

object

如果您可以在LINQ表达式中执行相同的操作,那么编译后的表达式也可以正常工作。但是,您可能不知道生成表达式时参数的实际类型,因此您可能希望采用不同的策略 - 在调用Convert.ChangeType方法时连接,该方法可以解包并转换为同一时间。