2017-05-29 57 views
0

我正在使用表达式树开发动态业务规则引擎。因此,我不确定编译期间的参数数量。我必须创建动态输入参数。使用动态输入参数的Expression.Lambda

对于这个要求,我使用Expression.Lambda像下面,但喜欢它的投掷的错误:

为拉姆达声明提供的参数的数量不正确

我可能是错的语法。我提到微软网站,他们正在用单个参数创建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

什么只是Expression.Lambda(...)? –

+0

表达式。Lambda是我用来从前面的操作中形成的表达式tress创建委托或者作为参数传递给其他函数的API函数,我没有在这里展示,我只是使用表达式树存储的表达式树变量ruleExpression –

+0

我也尝试了Plain.Lamda –

回答

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意愿真理genete一个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); 
+0

伟大的先生Xanatos,非常感谢你解释事物并提供代码示例。我尝试你的方法。 –