Как создать дерево выражений цикла - PullRequest
0 голосов
/ 15 марта 2019

Я пытаюсь создать дерево выражений, которое будет генерировать этот метод:

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

Я не понимаю, как работает LabelTarget. В моем случае нет значения, к которому я хочу перейти ... Я не понимаю, почему для этого требуется type.

Вот мой код:

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

Я получаю эту ошибку:

'variable 'cnt' of type 'System.Int32' referenced from scope '', but it is not defined'

1 Ответ

0 голосов
/ 15 марта 2019

Когда вы используете VariableExpression в блоке, вы должны передать эту переменную в параметр variables Expression.Block. Это то, что вызывает вашу ошибку.

Боюсь, у меня не было времени, чтобы подробно рассмотреть ваш код, но я переписал ваш C # с помощью выражений:

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