Explicit conversion of parameters in Expression Trees created from MethodInfo

Viewed 900

I have the method below which converts a (non-static) MethodInfo into a compiled Expression (Func) which I can then call.

This works great: I can call it with a method expecting both reference objects and value types.

BUT unlike the original method where I could call a method that had a parameter expecting a double and pass it an int this compiled expression doesn't support that and throws an InvalidCastException.

How do I modify this to support the same type of implicit casting that happens during a normal method call?

Bonus question: should the instanceExp use the DeclaringType or the ReflectedType from the 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();
}

--- EDIT

The working solution is:

var changeTypeMethod = typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(TypeCode) });
var arguments =
     methodParams.Select((p, i) =>
         !typeof(IConvertible).IsAssignableFrom(p.ParameterType)
             // If NOT IConvertible, don't try to convert it
             ? (Expression)Expression.Convert(
                 Expression.ArrayAccess(arrayParameter, Expression.Constant(i)), p.ParameterType)
            :
             // Otherwise add an explicit conversion to the correct type to handle int <--> double etc.
            (Expression)Expression.Convert(
                Expression.Call(changeTypeMethod,
                    Expression.ArrayAccess(arrayParameter, Expression.Constant(i)),
                    Expression.Constant(Type.GetTypeCode(p.ParameterType))),
                p.ParameterType)
        )
        .ToList();
1 Answers
Related