I have found little issue with expression trees and would like to know whether such is a bug or a feature. I have this code. The first function assigns one to a variable and returns it.
static class Functions
{
static public Expression<Func<int>> GetOne()
{
//Returns something like this () => {int x; return x +1;}
var variable = Expression.Variable(typeof(int));
var f = Expression.Lambda<Func<int>>(
Expression.Block(
new[] { variable },
Expression.Assign(variable, Expression.Add(variable, Expression.Constant(1)))
));
return f;
}
static public Expression<Func<int>> ApplyTenTimes()
{
var i = Expression.Variable(typeof(int));
var breakLabel = Expression.Label();
var f = GetOne();
var loop = Expression.Lambda<Func<int>>(
Expression.Block(
new[] { i },
Expression.Block(
new Expression[] {
Expression.Loop(Expression.Block(
Expression.IfThen(Expression.Equal(i, Expression.Constant(10)), Expression.Break(breakLabel)),
Expression.PostIncrementAssign(i),
Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Call( Expression.Invoke(f),typeof(int).GetMethod("ToString", new Type[0]))
))),
Expression.Label(breakLabel),
Expression.Invoke(f)
})));
return loop;
}
}
f = Functions.GetOne().Compile();
IEnumerable<int> a = Enumerable.Range(0, 9).Select(_ => f()).ToList();
//Prints 1
Console.WriteLine(f());
f = Functions.ApplyTenTimes().Compile();
//Prints 1, ..., 10, 1
Console.WriteLine(f());
I expected the f always prints 1 as 0 is a default value for int.
If you try to get an interpreted delegate when calling Compile
:
var f = Functions.ApplyTenTimes().Compile(preferInterpretation: true);
Console.WriteLine(f());
Then it behaves as you'd expect - "1" is printed eleven times.
Based on this fact, this is highly likely to be a bug in the expression compiler when compiling a loop expression, since the delegate should have the same behaviour regardless of whether it is interpreted or compiled.