2010-09-05 4 views
7

Je suis en train de construire un arbre d'expression dynamique comme ci-dessous:Problème lors de la construction d'expression dynamique arbre

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

Pour que j'utilise:

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

Mais le problème est Expression.Lambda jette un exception:

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

Je ne sais pas la question que mon bloc semble être 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 } 
} 

S'il vous plaît laissez-moi savoir ce que le problème pourrait être.

Répondre

10

La valeur d'un BlockExpression est juste la valeur de la dernière expression dans le bloc. Plutôt que d'inclure un ReturnExpression, laissez simplement la dernière expression être la valeur que vous voulez retourner.

De même, vous devez déclarer les expressions de paramètre pour le bloc en tant qu'argument séparé de la méthode Expression.Block. Vous les avez inclus dans la liste des expressions, ce qui les fera évaluer en tant qu'expressions mais ne les déclarera pas dans le bloc.

De plus, Expression.Increment "ne modifie pas la valeur de l'objet qui lui est transmis". Vous devrez donc placer vos expressions d'incrémentation dans les expressions d'affectation.

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

Ohh ... merci pour votre aide. Vraiment j'ai oublié que je dois faire assigner pour Increment. – abhishek

Questions connexes