代码之家  ›  专栏  ›  技术社区  ›  Levon Ravel

从作用域引用但未定义的Linq表达式

  •  1
  • Levon Ravel  · 技术社区  · 5 年前

    我试图创建一个使用两个参数的操作,一个参数是类实例,另一个是对象数组。当我找到具有属性的方法时,对象数组类型是未知的,因此我尝试了下面的方法,但是expr.Compile()抛出了一个错误

    “System.Object”类型的变量“arg1[0]从作用域“”引用,但未定义它

    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)=>转换(arg0,测试)。测试位置(转换(arg1[0],字符串),转换(arg1[1],Int32),转换(arg1[2],单个)

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

    从本质上说,我试图在编译表达式之后完成这项工作

    Action<T(anyclass reference), object[] (unknown params)>
    (arg0, arg1)=>{ Convert(arg0, T).Method(Convert(arg1[0], ToUnknownType))}
    
    1 回复  |  直到 5 年前
        1
  •  3
  •   Nkosi    5 年前

    在下面的狙击手里,

    //...
    
    //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;
    }