Monday, April 23, 2007

Ways to skin a LINQ query

Quite naturally, the very first step to understand LINQ is to go behind curtain and see how the magic select/where statement works. Although this has been explained many, many, many times, I still couldn't resist the temptation:

    public class Customer
    {
        public string Name { get; internal set; }
        public int Age { get; internal set; }
    }

    //...
            List<Customer> list = ...;
            var ret = from s in list
                      orderby s.Age descending
                      where s.Name == "Ming"
                      select s;
First, let's take out the syntax sugar out of the query. It's then equivalent to:
            Func<Customer, bool> p1
                = c => c.Name == "Ming";
            Func<Customer, int> p2
                = c => c.Age;
            return list.Where(p1).OrderByDescending(p2);
Still, this uses Lambda Expression. Taking that out, we have:
            var ret = list.Where<Customer>(
                new Func<Customer, bool>(
                    delegate(Customer c) {
                        return c.Name == "Ming";
                    }
            ));
            ret = ret.OrderByDescending<Customer, int>(
                new Func<Customer, int>(
                    delegate(Customer c) { return c.Age; }
            ));
And finally, without the Extension Method and var magic, the C# 2.0 way to write the query:
            IEnumerable<Customer> ret =
                System.Linq.Enumerable.Where<Customer>(
                    list,
                    new Func<Customer, bool>(
                        delegate(Customer c) {
                            return c.Name == "Ming";
                        }
            ));
            ret = System.Linq.Enumerable.
                OrderByDescending<Customer, int>(
                    ret,
                    new Func<Customer, int>(
                        delegate(Customer c) {
                            return c.Age;
                        }
            ));
It's now clear that LINQ is a compiler feature plus corresponding library support (System.Linq.Enumerable, for example). There really isn't anything new from CLR point of view.