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



Sunday, October 6, 2019

LINQ Expression Trees

An expression tree is an efficient data representation of a query operator lambda expression. This data representation is evaluated all simultaneously, so that an individual query can be built and launched on a data source in once

Consider the next query with two operators expecting delegates as arguments:


        private static decimal[] celsiusDegrees = new decimal[] 
            {0.0M, 6.0M, 14.0M, 25.0M, 28.0M, 34.0M, 36.0M};

        private static IEnumerable<decimal> enumerableTemps = celsiusDegrees
            .Where(i => i > 30.0M)
            .OrderBy(i => i).ToArray();

        private static IQueryable<decimal> queryableTemps = celsiusDegrees.Where(c => c > 30.0M)
            .OrderBy(c => c).AsQueryable();



When the first code is compiled .NET IL emits code with two anonymous methods, one for each of the query lambda expressions

This query is evaluated and launched linearly, first Where operator, then OrderBy operator. This linear evaluation has performance for this example, but consider a query on a large dataset. These scena is when Expression Trees become necessary. Expression trees will be generated if the operator is declared to accept an expression of a delegate

These are the two different implementations of the Where operator:

Standard query operator in LINQ to Objects API, in System.Linq.Enumerable class


        public static IEnumerable<T> Where<T>(
                this IEnumerable<T> source,
                Func<T, bool> predicate);



Implementation in the LINQ to SQL API, in the System.Linq.Queryable class


        public static IQueryable<T> Where<T>(
                this IQueryable<T> source,
                System.Linq.Expressions.Expression<Func<int, bool>> predicate);



The result of this code is the next


        Console.WriteLine(enumerableTemps);

        foreach (var temp in enumerableTemps)
            Console.WriteLine(temp);

        Console.WriteLine(Environment.NewLine);

        Console.WriteLine(queryableTemps);
        foreach (var temp in queryableTemps)
            Console.WriteLine(temp);





The ease way to create expression trees is by using advanced LINQ features, however, a tree made up only of constans would be converted automatically at compile time, the aim is build parametric expressions, such as the formula to convert celsius to kelvin degrees : K = C + 273.15


        Func<decimal, decimal> CelsiusToKelvin = (c) => c + 273.15M;

        Expression<Func<decimal, decimal>> CelsiusToKelvinExp = (c) => c + 273.15M;



The first delegate instance is no different from a regular function, you can get an expression tree representation instead of the delegate simply declaring CelsiusToKelvin as an Expression<TDelegate>

The result of this code is the next


            Console.WriteLine(CelsiusToKelvin.ToString());
            Console.WriteLine(CelsiusToKelvin(34.2M));

            Console.WriteLine(CelsiusToKelvinExp.ToString());
            Console.WriteLine(CelsiusToKelvinExp.Compile()(34.2M));