问题而建立动态防爆pression树动态、问题、pression

2023-09-03 11:27:31 作者:蒲公英的梦想

我想建立一个动态的前pression树如下图所示:

I am trying to build a dynamic Expression Tree like below :

 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();

但问题是防爆pression.Lambda抛出一个异常:

But the problem is Expression.Lambda throws an exception :

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

我不知道这个问题,因为我的块似乎是确定:

I dont know the issue as my block seems to be Ok:

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

请让我知道什么问题可以。

Please let me know what the problem could be.

推荐答案

一 BlockEx pression 是最后EX pression在该块刚值。而不是包括ReturnEx pression,只是让最后EX pression是要返回的值。

The value of a BlockExpression is just the value of the last expression in the block. Rather than including a ReturnExpression, just let the last expression be the value you want to return.

此外,您还需要声明ParameterEx pressions该块作为一个单独的参数防爆pression.Block方法。你已经列入他们的前pressions,这将导致他们被评价为EX pressions,但不会宣布他们在块列表中。

Also, you need to declare the ParameterExpressions for the block as a separate argument to the Expression.Block method. You have included them in the list of expressions, which will cause them to be evaluated as expressions but will not declare them in the block.

此外,防爆pression.Increment 不改变的价值传递给它,所以你需要包装在分配前pressions的增量EX pressions对象。

Also, Expression.Increment "does not change the value of the object that is passed to it", so you will need to wrap your increment expressions in assignment expressions.

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);