代码之家  ›  专栏  ›  技术社区  ›  abhishek

生成动态表达式树时出现问题

  •  9
  • abhishek  · 技术社区  · 14 年前

    我正在尝试构建一个动态表达式树,如下所示:

     Func<IEnumerable<int>, int, bool> dividesectionmethod = (x, y) =>
                {
                    int nos1 = 0;
                    int nos2 = 0;
                    foreach (int i in x)
                    {
                        if (i <= y)
                            nos1++;
                        else
                            nos2++;
                    }
                    return nos1 > nos2;
                };
    

    为此,我使用:

     ParameterExpression enumerableExpression = Expression.Parameter(typeof(IEnumerable<int>), "x");
                ParameterExpression intexpression = Expression.Parameter(typeof(int), "y");
    
                ParameterExpression localvarnos1 = Expression.Variable(typeof(int), "nos1");
                ParameterExpression localvarnos2 = Expression.Variable(typeof(int), "nos2");
                ConstantExpression zeroConstantintval = Expression.Constant(0);
                BinaryExpression bexplocalnos1 = Expression.Assign(localvarnos1, zeroConstantintval);
                BinaryExpression bexplocalnos2 = Expression.Assign(localvarnos2, zeroConstantintval);
    
                //As Expression does not support Foreach we need to get Enumerator before doing loop
    
                ParameterExpression enumerator = Expression.Variable(typeof(IEnumerator<int>), "enumerator");
                BinaryExpression assignenumerator = Expression.Assign(enumerator, Expression.Call(enumerableExpression, typeof(IEnumerable<int>).GetMethod("GetEnumerator")));
    
    
                var currentelement = Expression.Parameter(typeof(int), "i");
                var callCurrent = Expression.Assign(currentelement, Expression.Property(enumerator, "Current"));
    
                BinaryExpression firstlessequalsecond = Expression.LessThanOrEqual(currentelement, intexpression);
    
                MethodCallExpression movenext = Expression.Call(enumerator, typeof(IEnumerator).GetMethod("MoveNext"));
    
                LabelTarget looplabel = Expression.Label("looplabel");
                LabelTarget returnLabel = Expression.Label(typeof(bool), "retval");
    
                BlockExpression block = Expression.Block(enumerableExpression, intexpression, localvarnos1, localvarnos2,
                    bexplocalnos1, bexplocalnos2, Expression.Loop(Expression.IfThenElse(
                    Expression.NotEqual(movenext, Expression.Constant(false)),
                    Expression.IfThenElse(firstlessequalsecond, Expression.Increment(localvarnos1), Expression.Increment(localvarnos2)),Expression.Break(looplabel)), looplabel),
                    Expression.Return(returnLabel, Expression.LessThan(localvarnos1, localvarnos2)));
    
                Expression<Func<IEnumerable<int>, int, bool>> lambda = Expression.Lambda<Func<IEnumerable<int>, int, bool>>(block, Expression.Parameter(typeof(IEnumerable<int>), "x"),
                    Expression.Parameter(typeof(int), "y"));
    
    
                Func<IEnumerable<int>, int, bool> mymethod = lambda.Compile();
    

    但问题是表达式。Lambda引发异常:

    Expression of type 'System.Void' cannot be used for return type 'System.Boolean'
    

    我不知道这个问题,因为我的街区似乎没问题:

    .Block() {
        $x;
        $y;
        $nos1;
        $nos2;
        $nos1 = 0;
        $nos2 = 0;
        .Loop  {
            .If (.Call $enumerator.MoveNext() != False) {
                .If ($i <= $y) {
                    .Increment($nos1)
                } .Else {
                    .Increment($nos2)
                }
            } .Else {
                .Break looplabel { }
            }
        }
        .LabelTarget looplabel:;
        .Return retval { $nos1 < $nos2 }
    }
    

    请告诉我有什么问题。

    1 回复  |  直到 14 年前
        1
  •  12
  •   Quartermeister    14 年前

    a的价值 BlockExpression 只是块中最后一个表达式的值。与其包含ReturnExpression,不如让最后一个表达式成为您想要返回的值。

    此外,还需要将块的ParameterExpressions声明为表达式.块方法。您已将它们包括在表达式列表中,这将导致它们作为表达式进行计算,但不会在块中声明它们。

    也, Expression.Increment “不更改传递给它的对象的值”,因此需要将增量表达式包装在赋值表达式中。

    BlockExpression block = Expression.Block(
        new ParameterExpression[] { 
            localvarnos1, localvarnos2, enumerator, currentelement },
        bexplocalnos1, 
        bexplocalnos2, 
        assignenumerator, 
        Expression.Loop(
            Expression.IfThenElse(
                Expression.NotEqual(movenext, Expression.Constant(false)),
                Expression.Block(
                    callCurrent, 
                    Expression.IfThenElse(
                        firstlessequalsecond, 
                        Expression.Assign(
                            localvarnos1, 
                            Expression.Increment(localvarnos1)), 
                        Expression.Assign(
                            localvarnos2, 
                            Expression.Increment(localvarnos2)))),
                Expression.Break(looplabel)), 
            looplabel),
        Expression.LessThan(localvarnos1, localvarnos2));
    
    Expression<Func<IEnumerable<int>, int, bool>> lambda = 
        Expression.Lambda<Func<IEnumerable<int>, int, bool>>(
            block,
            enumerableExpression,
            intexpression);