我正在使用Expression Tree开发动态业务规则引擎。因此,我不确定编译期间的参数数量。我必须创建动态输入参数。
对于这个要求,我正在使用如下的Expression.Lambda,但它的抛出错误如:
为lambda声明提供的参数数量不正确
我的语法可能有问题。我提到了Microsoft站点,他们正在创建具有单个参数的Func,而不是参数数组。
即使有大约16个参数,它们也会单独声明每个参数,例如Func< T1,T2,T3,T4,T5...T16 >
https://msdn.microsoft.com/en-us/library/dd402862(v=vs.110).aspx
是否有任何解决方法而不是单独声明我们可以作为数组传递吗?
var lambdaExpression = Expression.Lambda< Func< T[], bool>>(ruleExpression, pe).Compile();
在上面的语法中,pe是具有多个参数的ParameterExpression[]
数组。
在上面的语法而不是T[]
数组中,如果我使用单独的T元素,它的工作正常如
var lambdaExpression = Expression.Lambda< Func< T,T, bool>>(ruleExpression, pe).Compile();
但问题是在编译期间不知道T的数量。
如果我在这里做错了,请纠正我。
答案 0 :(得分:1)
创建具有运行时分配的参数数量的委托的简单示例。我认为这几乎是无用的(因为你必须通过DynamicInvoke
调用委托......你没有任何安全性,而且你使用的是最慢的反射执行方法。)
public static Delegate CreateLambda(int num)
{
var parameters = new ParameterExpression[num];
for (int i = 0; i < num; i++)
{
parameters[i] = Expression.Parameter(typeof(int), "p" + i);
}
// We sum all the parameters together
Expression sum = parameters[0];
for (int i = 1; i < num; i++)
{
sum = Expression.Add(sum, parameters[i]);
}
Expression body = sum;
LambdaExpression exp = Expression.Lambda(body, parameters);
return exp.Compile();
}
Expression.Lambda
实际上会生成一个Expression<Func<...>>
(或Expression<Action<...>>
),其中Func<...>
根据给定的参数计算,但Expression<...>
是一个LambdaExpression
的子类。如果Func<>
或Action<>
的参数太多,则甚至会在运行时生成委托类型。
然后:
int num = 5;
Delegate del = CreateLambda<double>(num);
// Note that we have to convert to object the various parameters,
// because DynamicInvoke uses a object[]
object[] values = Enumerable.Range(1, num).Select(x => (object)(double)x).ToArray();
double result = (double)del.DynamicInvoke(values);
Console.WriteLine("{0}={1}", string.Join("+", values), result);
如果你想拥有一个Func<T[], T>
,这是可能的(而且可能是一个更好的主意):
public static Func<T[], T> CreateLambda<T>(int num)
{
var parameter = Expression.Parameter(typeof(T[]), "p");
// We sum all the parameters together
Expression sum = Expression.ArrayIndex(parameter, Expression.Constant(0));
for (int i = 1; i < num; i++)
{
sum = Expression.Add(sum, Expression.ArrayIndex(parameter, Expression.Constant(i)));
}
Expression body = sum;
var exp = Expression.Lambda<Func<T[], T>>(body, parameter);
return exp.Compile();
}
您只需使用Expression.ArrayIndex()
。
然后例如:
int num = 5;
Func<double[], double> del = CreateLambda<double>(num);
double[] values = Enumerable.Range(1, num).Select(x => (double)x).ToArray();
double result = del(values);
Console.WriteLine("{0}={1}", string.Join("+", values), result);