I am trying to create an expression tree that would generate this method:
public static int Print(int i) {
int cnt = 0;
int sum = 0;
while (true) {
if (cnt >= i) {
Console.WriteLine(sum);
break;
}
sum = sum + cnt;
cnt++;
}
return sum;
}
I do not understand how the LabelTarget
works.In my case there is no value that i want to jump to...I do not understand why it does require a type
.
Here is my code so far:
public static Func<int,int> MakeExpression() {
//input
ParameterExpression parameter = Expression.Parameter(typeof(int));
//define local variables and initialize them
Expression cntVarExpr = Expression.Variable(typeof(int),"cnt");
Expression sumVarExpr = Expression.Variable(typeof(int), "sum");
Expression initCntExpr = Expression.Assign(cntVarExpr, Expression.Constant(0));
Expression initSumExpr = Expression.Assign(sumVarExpr, Expression.Constant(0));
//loop condition
Expression condExpr = Expression.GreaterThanOrEqual(cntVarExpr, parameter);
//block if true
MethodInfo method = typeof(Console).GetMethod("WriteLine",new Type[] { typeof(int)});
Expression printExpr = Expression.Call(null, method,cntVarExpr); //static method
LabelTarget label = Expression.Label(typeof(int)); //am not sure about this one ? what
Expression bkExpr = Expression.Break(label, sumVarExpr);
BlockExpression block = Expression.Block(printExpr, bkExpr);
//loop body
Expression ifExpr = Expression.IfThen(condExpr, block);
Expression addExpr = Expression.AddAssign(sumVarExpr,cntVarExpr);
Expression incrExpr = Expression.Add(cntVarExpr, Expression.Constant(1));
BlockExpression loopBodyExpr = Expression.Block(ifExpr, addExpr,incrExpr);
LoopExpression loopExpr = Expression.Loop(loopBodyExpr);
//method body
Expression returnExpr = Expression.Return(label, sumVarExpr,typeof(int));
//final expression
BlockExpression bigExpression = Expression.Block(initCntExpr, initSumExpr, loopExpr, returnExpr);
var meth = Expression.Lambda<Func<int, int>>(bigExpression,parameter).Compile();
return meth;
}
I keep getting this error:
'variable 'cnt' of type 'System.Int32' referenced from scope '', but it is not defined'
When you use a VariableExpression
in a block, you have to pass that variable into the variables
parameter of Expression.Block
. This is what's causing your error.
I'm afraid I didn't have time to go through your code in detail, but I rewrote your C# using expressions:
var i = Expression.Parameter(typeof(int), "i");
var cnt = Expression.Variable(typeof(int), "cnt");
var sum = Expression.Variable(typeof(int), "sum");
var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) });
var breakLabel = Expression.Label("break");
var loop = Expression.Loop(
Expression.Block(
Expression.IfThen(
Expression.GreaterThanOrEqual(cnt, i),
Expression.Block(
Expression.Call(writeLineMethod, Expression.Convert(sum, typeof(object))),
Expression.Break(breakLabel))),
Expression.AddAssign(sum, cnt),
Expression.PostIncrementAssign(cnt)),
breakLabel);
var block = Expression.Block(new[] { cnt, sum },
Expression.Assign(cnt, Expression.Constant(0)),
Expression.Assign(sum, Expression.Constant(0)),
loop,
sum);
var method = Expression.Lambda<Func<int, int>>(block, new[] { i }).Compile();