Posts

....
Technical Blog for .NET Developers ©

Thursday, October 10, 2019

Constructing Expression Trees

Constructing Expression Trees in runtime encapsulates the logic of the tree into the Expression

In this post we have an example of Construct and Compile Lambda Expression, with a simple logic, the function receives a name and a number of request days, and for each day adds it to the result


            var test = ConstructRuntimeFunction();

            var i = test("test", 4);

            //
            //"test, 0 added, 1 added, 2 added, 3 added, 4 added"



The expression before compile is the next tree:



The implementation of ConstructRuntimeFunction is the next:



        static Func<string, int, string> ConstructRuntimeFunction()
        {
            var prmA = Expression.Parameter(typeof(string), "name");

            var prmB = Expression.Parameter(typeof(int), "request_days");

            var loopDays = Expression.Variable(typeof(int), "loop_days");

            var dayDate = Expression.Variable(typeof(DateTime), "day_date");

            var result = Expression.Variable(typeof(string), "result");

            var loopEnd = Expression.Label();

            MethodInfo method_add_day = Assembly.GetExecutingAssembly().GetType("Test").GetMethod("increaseDay");

            MethodInfo method_write = Assembly.GetExecutingAssembly().GetType("Test").GetMethod("addVisitDay");

            var func = Expression.Lambda<Func<string, int, string>>(

                Expression.Block(new[] { result }, Expression.Assign(result, prmA),

                Expression.Block(new[] { loopDays }, Expression.Assign(loopDays, Expression.Constant(0)),

                Expression.Block(new[] { dayDate }, Expression.Assign(dayDate, Expression.Constant(DateTime.Now))),

                Expression.Loop(
                    Expression.Block(
                        Expression.IfThen(
                            Expression.Not(
                                Expression.LessThanOrEqual(loopDays, prmB)),
                                Expression.Break(loopEnd)),

                    Expression.Block(new[] { dayDate }, Expression.Assign(dayDate, Expression.Call(method_add_day, loopDays))),

                    Expression.Assign(result, Expression.Call(method_write, result, loopDays)),

                    Expression.PostIncrementAssign(loopDays)),

                loopEnd)),

            result), prmA, prmB);
            
            return func.Compile();
        }