Search code examples
c#expression-trees

Stuck In Expression Trees


I am trying to understand this example and I keep failing.

This is the code:

// Creating a parameter expression.
ParameterExpression value = Expression.Parameter(typeof(int), "value");

// Creating an expression to hold a local variable. 
ParameterExpression result = Expression.Parameter(typeof(int), "result");

// Creating a label to jump to from a loop.
LabelTarget label = Expression.Label(typeof(int));

// Creating a method body.
BlockExpression block = Expression.Block(
    // Adding a local variable. 
    new[] { result },
    // Assigning a constant to a local variable: result = 1
    Expression.Assign(result, Expression.Constant(1)),
    // Adding a loop.
        Expression.Loop(
    // Adding a conditional block into the loop.
           Expression.IfThenElse(
    // Condition: value > 1
               Expression.GreaterThan(value, Expression.Constant(1)),
    // If true: result *= value --
               Expression.MultiplyAssign(result,
                   Expression.PostDecrementAssign(value)),
    // If false, exit the loop and go to the label.
               Expression.Break(label, result)
           ),
    // Label to jump to.
       label
    )
);

I know partially what is going on but that label is confusing me so my questions are what is a label and how is that local value begin assigned and used in first item of the block?


Solution

  • A label identifies a loop. I can understand your confusion, since C# doesn't actually have loop labels, but .NET does use them internally and they are therefore used in .NET's expression trees. Here's some example Java code (which does have loop labels):

    outerLoop: // This is a label for the outer loop
    while (true) {
        innerLoop: // This is a label for the inner loop
        while (true) {
            // Rather than exiting the inner loop (which is what a plain break would
            // do), this exits the outer loop
            break outerLoop;
        }
    }
    

    The Expression.Loop method takes a label as an argument, which says "this label refers to this loop". When you have Expression.Break(label, result), it says "break out of the loop that this label refers to", which in this case is the block's single loop.

    For the local variable, Expression.Block's first argument declares all the local variables scoped to that block. So result is first declared, then initialized by the Expression.Assign call.

    The resulting expression tree is approximately equivalent to this C# code:

    {                      // Expression.Block(
        int result;        //   new[] { result },
        result = 1;        //   Expression.Assign(result, Expression.Constant(1)),
        while (true)       //   Expression.Loop(
        {                  
            if (value > 1) //     Expression.IfThenElse(
            {              //       Expression.GreaterThan(value, Expression.Constant(1)),
                result *=  //       Expression.MultiplyAssign(result,
                  value--; //       Expression.PostDecrementAssign(value)),
            }
            else             
            {
                break;     //       Expression.Break(label, result)
            }              //     ),
        }                  //   label)
    }                      // )