Problem building a dynamic expression tree

I am trying to create a dynamic expression tree as shown 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; }; 

For this, I use:

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

But the problem in Expression.Lambda throws an exception:

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

I don't know how my block looks normal:

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

+7
c # lambda
source share
1 answer

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

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

In addition, Expression.Increment "does not change the value of the object passed to it," so you will need to wrap the expressions in the 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); 
+10
source share

All Articles