gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 01:02:00 25 4
gpt4 key购买 nike

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

效果很好:我可以使用既需要引用对象又需要值类型的方法来调用它。

但与原始方法不同,在原始方法中我可以调用一个方法,该方法的参数需要一个 double 并将其传递给一个 int 这个编译后的表达式不支持并抛出一个 InvalidCastException

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

额外的问题:instanceExp 应该使用 MethodInfo 中的 DeclaringType 还是 ReflectedType

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

--- 编辑

工作解决方案是:

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

最佳答案

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

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

原因是 a 是一个 object,所以为了使它成为一个 double 强制转换必须解包它,然后转换intdouble。该语言只允许转换做一件事——它要么解包要么转换,但不能同时做。您需要通过告诉编译器在 object 中包含一个 int 来告诉编译器如何显式执行此转换:

double b = (double)((int)a); // Works

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

关于c# - 从 MethodInfo 创建的表达式树中参数的显式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36191099/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com