我有下面的方法,将(非静态)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();
}
答案 0 :(得分:4)
问题与这段C#代码相同:
object a = 123;
double b = (double)a; // InvalidCastException
原因是a
是object
,因此为了使其成为double
,演员必须解开它,然后将int
转换为{{ 1}}。该语言允许演员只做一件事 - 它将展开或转换,但不是两者。您需要告诉编译器如何明确地执行此操作,方法是告诉它double
内包含int
:
object
如果您可以在LINQ表达式中执行相同的操作,那么编译后的表达式也可以正常工作。但是,您可能不知道生成表达式时参数的实际类型,因此您可能希望采用不同的策略 - 在调用Convert.ChangeType
方法时连接,该方法可以解包并转换为同一时间。