2010-09-05 58 views
7

我想建立一个动态的表达式树象下面这样:问题,同时建立动态表达式树

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() { 
    $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 } 
} 

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

回答

10

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

此外,您需要声明该块的ParameterExpressions作为Expression.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); 
+0

哦...谢谢你的帮助。真的,我忽略了我必须为Increment赋值。 – abhishek 2010-09-05 15:03:29