c# - 构建动态表达式树时出现问题

标签 c# .net lambda

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

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

但问题是 Expression.Lambda 抛出异常:

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

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

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

请让我知道可能是什么问题。

最佳答案

BlockExpression 的值只是 block 中最后一个表达式的值。不要包含 ReturnExpression,只需让最后一个表达式成为您要返回的值即可。

此外,您需要将 block 的 ParameterExpressions 声明为 Expression.Block 方法的单独参数。您已将它们包含在表达式列表中,这将导致它们被评估为表达式但不会在 block 中声明它们。

此外,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);

关于c# - 构建动态表达式树时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3646283/

相关文章:

java - xamarin如何编译到android?

c# - 将 Generic<Derived> 转换为 Generic<Base>

c# - 在列表中选择与界面匹配的项目

java - 使用 Java 流将对象映射到多个对象

c++ - 代码块和 lambdas c++11

c# - Expression.PropertyOrField 可以用于访问静态属性或字段吗?

c# - 授权过滤器在我的 mvc 项目中不起作用

c# - C#/.NET 4.0+ 实现可取消后台线程的方法是什么?

c# - 将 BindingList<T> 转换为 T 数组

c# - 为什么我不能访问 DelegateCommand 的执行委托(delegate)中的实例属性?