LINQ - Why building expression tree instead of reflection?

Posted on 2009-04-25 01:09  wyatt_chen  阅读(1483)  评论(6)    收藏  举报
 

LINQ - Why building expression tree instead of reflection?

 

 

Context:

 

After .net framework 3.5, more and more developers come to love the techniques due to its good extending ability and flexibility. If you understand the way LISP do, it might be better to grasp the essence of expression.

 

Introduction:

 

Since c# 3.0, Microsoft introduced LINQ that impressed me most among all the new features. However, it seems a little bit tricky due to the evolution from delegate. But, expression can offer more flexibility for developers.

 

Here, I will try to explain LINQ expression from the scratch, so that might benefit new comers to understand the way it works.

 

First thing first, what is LINQ expression tree? Generally speaking, it is abstract syntax tree or somewhat data structure. Through analyzing expression tree, we can implement some specific functionality. By using Lambda expression, we can save lines of code to fulfill the function like below:

 

Expression<Func<T,bool>> expression = value => (value & 1) == 1;

Func<T,bool> func = value => (value & 1) == 1;

 

Now, got the difference?

Obviously, first one is using second one (TDelegate) as parameter. Above is just a simple symbol to define the syntax difference. Now, let dig it further using another more elaborate case:

 

We define a simple class below:

class Champion

        {

            public Champion(string name, string city)

            {

                this.Name = name;

                this.City = city;              

            }

            public string Name { get; set; }

            public string City { get; set; }           

        }

 

And define two different methods to dynamically build it, one is using our old favorite but populor reflection way:

 

static Func<T, bool> BuildFunctionFor<T>(string prop, object val)

            {

                return t => t.GetType().InvokeMember(prop, System.Reflection.BindingFlags.GetProperty, null, t, null) == val;

            }

 

Another way is our topic – building expression.

 

static Func<T,bool> BuildFunctionExpFor<T>(string prop, object val)

            {

               

                ParameterExpression exp = Expression.Parameter(typeof(T), "t");

                MemberExpression left = (MemberExpression)Expression.Property(exp, prop);

                ConstantExpression right = Expression.Constant(val);

                BinaryExpression binExp = Expression.Equal(left, right);

                Expression<Func<T, bool>> expression = Expression.Lambda<Func<T, bool>>(binExp, exp);

                return expression.Compile();

            }

 

 

Now, let us execute it

        

            var ChampionComeFromBoston = FunctionFactory.BuildFunctionFor<Champion>("City", “Boston”);

 

or

             var ChampionComeFromBoston = FunctionFactory.BuildFunctionExpFor<Champion>("City", “Boston”);

 

            var bostonP = ChampionGroup.Where<Champion>(ChampionComeFromBoston);

            if (bostonP.Any<Champion>())

                bostonP.ToList().ForEach(p => Console.WriteLine(" We would like to know {0} is NBA Finals Champion ",p.Name));

            Console.ReadLine();

 

Both methods can be executed perfectly up until now, can we say: the first one is the best due to being concise and succinct. Actually, we can compare the IL and easily to draw this conclusion.

  

 

 

                                                 IL of reflection

 

 

  

                                          IL of expression.

 

Now, let adding more spicy seasonings by doing some modification on our Champion class.

       enum City

        {

            Boston,

            Houston,

            Dallas,

        }

        class Champion

        {

 

            public Champion(string name, City city)

            {

                this.Name = name;

                this.City = city;              

            }

            public string Name { get; set; }

            public City City { get; set; }

           

        }

 

And executing code:

 

var ChampionComeFromBoston = FunctionFactory.BuildFunctionFor<Champion>("City", City.Boston);

 

or

var ChampionComeFromBoston = FunctionFactory.BuildFunctionFor<Champion>("City", City.Boston);

 

 

            var bostonP = ChampionGroup.Where<Champion>(ChampionComeFromBoston);

            if (bostonP.Any<Champion>())

                bostonP.ToList().ForEach(p => Console.WriteLine(" We would like to know {0} is coming ",p.Name));

            Console.ReadLine();

 

Now, we should be able to see the advantage of building expresion. We don’t even do any bit change, it still can be excuting perfectly, but not for reflection method.

 

Summary:

 

Comparing the above case, do you get any sense why microsoft introduce LINQ expression in latest framework?

 

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3