从范围引用的 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;
}
我正在尝试创建一个使用两个参数的动作,其中一个参数是 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;
}