Reputation: 8791
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?
Upvotes: 3
Views: 374
Reputation: 4153
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)
} // )
Upvotes: 1