从范围引用的 Linq 表达式但未定义

Linq Expression referenced from scope but its not defined

我正在尝试创建一个使用两个参数的动作,其中一个参数是 class 实例,另一个是对象数组。对象数组类型未知,因为我找到了带有属性的方法,所以我尝试了下面的方法,但是 expr.Compile() 抛出错误

variable 'arg1[0]' of type 'System.Object' referenced from scope '', but it is not defined

public static T BuildDelegate<T>(MethodInfo method)
{
    var dgtMi = typeof(T).GetMethod("Invoke");
    var dgtParams = dgtMi.GetParameters();
    var preDeterminedParams = new ParameterExpression[2]
    {
         Expression.Parameter(dgtParams[0].ParameterType, "arg0"),
         Expression.Parameter(typeof(object[]), "arg1") 
    };

    var methodParams = method.GetParameters();
    var paramThis = Expression.Convert(preDeterminedParams[0], method.DeclaringType);
    var paramsToPass = CreateParam(methodParams);
    var expr = Expression.Lambda<T>(
        Expression.Call(paramThis, method, paramsToPass),
        preDeterminedParams);
    return expr.Compile();
}
private static Expression[] CreateParam(ParameterInfo[] parameters)
{
    var expressions = new Expression[parameters.Length];
    for (int i = 0; i < parameters.Length; i++)
    {
        //Trying to create a placeholder for any objects that might be passed through arg1
        expressions[i] = Expression.Convert(
                         Expression.Parameter(typeof(object), "arg1[" + i + "]"),
                         parameters[i].ParameterType);
    }
    return expressions;
}

expr 在尝试编译之前看起来像这样

(arg0, arg1) => Convert(arg0, Test).TestingInvocation(Convert(arg1[0], String), Convert(arg1[1], Int32), Convert(arg1[2], Single)

我猜因为 arg1[0] 是在 CreateParam() 中作为占位符创建的,所以它没有参考值。不知道如何创建一个holder,所以它可以有一些参考。

基本上我是在编译表达式后尝试完成此操作

Action<T(anyclass reference), object[] (unknown params)>
(arg0, arg1)=>{ Convert(arg0, T).Method(Convert(arg1[0], ToUnknownType))}

在以下代码段中,

//...

//Trying to create a placeholder for any objects that might be passed through arg1
expressions[i] = Expression.Convert(
                 Expression.Parameter(typeof(object), "arg1[" + i + "]"),
                 parameters[i].ParameterType);

//...

你基本上是在做 arg1[0] => ...,这不是一个有效的表达式。

您很可能正在寻找 Expression.Array* 相关调用以访问数组索引。

public static T BuildDelegate<T>(MethodInfo method) {
    var dgtMi = typeof(T).GetMethod("Invoke");
    var dgtParams = dgtMi.GetParameters();
    var preDeterminedParams = new ParameterExpression[2] {
         Expression.Parameter(dgtParams[0].ParameterType, "arg0"),
         Expression.Parameter(typeof(object[]), "arg1")
    };

    ParameterInfo[] methodParams = method.GetParameters();
    var paramThis = Expression.Convert(preDeterminedParams[0], method.DeclaringType);
    // arg1 =>
    var arg1 = preDeterminedParams[1];
    // arg1 => Convert(arg1[0], SomeType), Convert(arg1[1], SomeType), ....
    var paramsToPass = CreateParam(arg1, methodParams);
    var expr = Expression.Lambda<T>(
        Expression.Call(paramThis, method, paramsToPass),
        preDeterminedParams);

    return expr.Compile();
}

private static Expression[] CreateParam(ParameterExpression arg1, ParameterInfo[] parameters) {
    var expressions = new Expression[parameters.Length];
    for (int i = 0; i < parameters.Length; i++) {
        //arg1 => Convert(arg1[i], SomeType)
        expressions[i] = Expression.Convert(
            Expression.ArrayIndex(arg1, Expression.Constant(i)), parameters[i].ParameterType
        );
    }
    return expressions;
}