Demystifying C# 3.0 - Part 6: (LINQ) Query Expression Translation (to C# 3.0)

Posted on 6/30/2006 @ 8:47 PM in #Vanilla .NET by | Feedback | 23093 views

In this series of Demystifying C# 3.0 we have already covered -

a) Demystifying C# 3.0 - Part 1: Implicitly Typed Local Variables "var"
b) Demystifying C# 3.0 - Part 2: Anonymous Types
c) Demystifying C# 3.0 - Part 3: Extension Methods
d) Demystifying C# 3.0 - Part 4: Lambda Expressions
e) Demystifying C# 3.0 - Part 5: Object and Collection Initializers

I *strongly* recommend reading up the above in sequence before reading this post. This is, (I feel) a rather good post, that will set LINQ in your mind clearly. If you rush through this post, you will waste this opportunity. If you are crystal clear about the above 5 posts and the concepts behind them, .. read on ..

Okay good, so in this post, we are going to talk about "Queries" or "LINQ" for the very first time in this Demystifying C# series. I have been asked in comments to talk about the practical application of the new C# 3.0 thingies. I can come up with seemingly lame practical applications, because the real awesome practical application - IS - LINQ (Language Integrated Query).

The practical application of the above 5 C# 3.0 features (which are not the complete set of new things in C# 3.0), can best be understood by understanding Query Expression Translation.

LINQ, as you may already know, looks like TSQL queries, except they are twisted upside down, and written in right inside of C#. You have probably already heard about the benefits, so I won't go into those for now. In here, we are going to talk about Query Expression Translation. You can write queries in LINQ using various keywords such as "from", "where", "select" etc.

Those queries, get translated into plain vanilla C# 3.0 code, and only then type-binding, overload resolution etc. happens. Once the Query has been translated to C#, it is then executed as regular method invocations - where of course you have various C# protections such as a method being missing, data types mismatched so on and so forth.

So, LINQ -->  Query --> TranslatedToC#3.0 --> Method Invocation.

So LINQ = Method Invocation? YES - THAT IS WHAT MAKES LINQ, Nothing but Plain vanilla C# 3.0. All those new language constructs, along with Query Expression Translation, make LINQ possible.

Lets understand with the help of an example.

In my last post Demystifying C# 3.0 - Part 5: Object and Collection Initializers, I had a simple example demonstrating Object & Collection Initializers. Basically, we got a List<Monkey> back as shown below -

var theWhiteHouseStaff =
    new List<Monkey>
    {
        new Monkey{ Name = "George W Bush", Age = 16},
        new Monkey{ Name = "Donald Rumsfield", Age = 16},
        new Monkey{ Name = "Condolezza Rice", Age = 16},
        new Monkey{ Name = "Dick Cheney", Age = 16}

    } ;

It is notable that List<T> implements IEnumerable<T>, so the above is a queryable object. So, you could write a query, that looks like -

var q =
    from staff in theWhiteHouseStaff

    select new {staff.Name} ;

Practical Application: "var q" <-- Anonymous Type (+). An anonymous type that holds an Anonymous Type with one property "staff.Name". Also, "var" lets you create an Implicitly typed local variable (+) . This means,
   a) You didn't have to declare/write a class structure to hold a type with one property called "Name" of data type string.
   b) You don't have to maintain that either - you can change the structure of the above query, and "it just works" :)

Now, the above query, can also be written like this -

var q =
    from staff in theWhiteHouseStaff

    select new { Name = staff.Name } ;

Practical Application: "new { Name = staff.Name }" <-- Object Initializer (+). The anonymous type, is being initialized by an Object Initializer. The anonymous type doesn't have logic, or a constructor. But it does have public setters on it's properties, so there you go - the Object Initializer can now take advantage of those, and the query is slowly decomposing into plain vanilla C# 3.0.

The above query, further decomposes into the below -

var q = theWhiteHouseStaff.Select(staff => new {staff.Name}) ;

WHOAA !!!, lets look at this query once again, only color coded this time ;-)

var q = theWhiteHouseStaff.Select(staff => new {staff.Name}) ;

(PS: If the RSS Feed eats the color coding, I suggest you come see it on my blog)

Practical Application:
   The yellow var q, is an Anonymous Type (+) "q", the "var" lets you create an implicitly typed local variable (+).
   The theWhiteHouseStaff is an IEnumerable<T>
   The green Select is an Extension Method  (+).
   The Gray staff => new { staff.Name } is a Lambda expression (+) that is participating in type-inference (+).
   and the new {staff.Name} is an Object Initializer (+).

So, the LINQ Query

var q =
    from staff in theWhiteHouseStaff

    select new {staff.Name} ;

is *absolutely* the same as the C# 3.0 language construct -

var q = theWhiteHouseStaff.Select(staff => new {staff.Name}) ;

Thus, the (Linq) query expression has been translated (to plain vanilla C# 3.0). This is called as Query Expression Translation, and this is the reason behind C# 3.0 enhancements.
 
:)

Cool huh?

 

Sound off but keep it civil:

Older comments..


On 9/4/2006 1:48:07 AM Maulikk said ..
var q =


from staff in theWhiteHouseStaff


select new {staff.Name} ;

In the above snippet how does the "staff" gets populated with the values?? what is the type of staff and why?

Thanks in advance


Maulik


On 9/4/2006 6:25:49 AM Augustin Prasanna said ..
The way in which you explain in fantastic. good one.


On 9/4/2006 3:26:07 PM Sahil Malik said ..
Maulikk - excellent Q.

C# 3.0 (oh heck C# vNext - thanks to .NET 3.0/WinFX Confusion) - does a lot of stuff under the scenes. You don't have to explicitly populate "staff" - it is there for you, for the query. Basically makes our life simple. It's an anonymous type.


On 9/4/2006 3:28:31 PM Sahil Malik said ..
Thanks Augustin - y'know it used to be even better, until people started getting offended by my weird sense of crass humor. :)


On 4/10/2007 8:08:15 AM mike123 said ..
Awesome articles and great way of explaining!!!


On 4/10/2007 9:16:00 AM Sahil Malik said ..
Thanks Mike123 :)


On 1/17/2008 6:33:27 AM Ajay said ..
I thoroughly enjoyed reading your articles. Very informative indeed. Do you have any more on this series or related? Is it possible to use LINQ queries on XML documents? I am looking at using XML's in a c# Silverlight application.


On 8/28/2008 11:04:01 AM Anton said ..
If only you could use LINQ to:


theWhiteHouseStaff.Remove("George W Bush");


theWhiteHouseStaff.Submit();


On 9/5/2008 2:36:28 PM Kaushik said ..
can u please explain this :


//CODE 1


public static T? Select<T>(this T? x, Func<T, T> selector)


where T : struct {


return x.HasValue ? new T?(selector(x.Value)) : null;


}

//CODE 2


public static double? Abs(double? x) {


return from d in x select Math.Abs(d);


}

1) How does the 'select' of code 2 calles 'Select' of code 1 (Case sensitivity)


2) How does 'd' in code 2 is infered as double and not double? ; since its part of x which is double?


3) how do i get this from select clause working ...since x is not a collection.


On 10/13/2008 7:23:02 AM vishal said ..
how to handle null values in these?


On 4/28/2009 1:45:33 AM manas said ..
I have two xmls which are to be accessed using single Linq query.


(XML1)


<?xml version="1.0" encoding="utf-8" standalone="yes"?>


<employees>


<employee>


<empcode>emp1</empcode>


<empname>empname</empname>


<kra>


<products></products>


<customers></customers>


<quality></quality>


<personnel></personnel>


</kra>


</employee>


</employees>


(XML2)


<?xml version="1.0" encoding="utf-8" standalone="yes"?>


<employees>

<employee>


<empcode>emp2</empcode>


<empname>empname</empname>


<kra>


<products></products>


<customers></customers>


</kra>


</employee>

</employees>

Now in two xmls i want to insert info in products,customers,quality,personnel tags in xml1 and in products,customers in xml2 using general linq query.


can u throw some light on this using c# code


Thanks


Manas


On 4/30/2009 3:12:21 PM Jon said ..
I'm having trouble figuring out what's going on here.

First off: new {staff.Name} looks unlike the object initializers from your previous article, where you had things like new Monkey { Name = "George" }. Why is there no type? What property is it setting?

Secondly: what is the value of var q? It's difficult for me to determine exactly what's being selected and how when I don't know what the result is. Is q a collection? Is it an object? Is it a collection of objects?

So confused!


On 6/3/2009 11:07:44 PM Tired Old Fart said ..
Sahil Malik: Your 'cuteness' in denigrating George W. Bush and his senior staff in your code example is pathetic. Perhaps you have noticed that your 'savior' Obama is in the process of validating ALL of the Bush doctrines and actions. You are the type who will be the first to shit-your-pants if a terrorist ever looks sideways at you. Best regards, asshole, and maybe, just maybe you'll never have to look death in the face; and, you can die happily with your tiny little wank snug in you hand. T L Shipley 03June2009


On 6/4/2009 3:16:33 PM Sahil Malik said ..
TL Shipley - I have the ultimate respect for GW Bush.


.. and .. I am going to keep politics off of my site.


On 12/18/2009 6:06:12 PM John said ..
Well I'm still mystified cause I tried this and I can't see how it brings the data back. All I get are new objects not the data. A simple Console print statement would have helped to show how to write out or display the data.