user6048670
user6048670

Reputation: 2887

I need help understanding LINQ. Where is my understanding going wrong?

I'll give you my best attempt at understanding it and you let me know where I'm going wrong.

For simplicity, let's assume that we live in a word that only has

I want to dissamble what happens when I do

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
                            where i % 2 == 1
                            orderby i descending
                            select i; 
foreach ( var i in Filtererd ) 
{
   Console.WriteLine(i);
}

What I understand first of all is that the query itself does not create a Ienumerable<int>; it creates and Expression Tree associated with the query. The elements returned by the query are yielded in an invisible function created by the compiler like

public static IEnumerable<int> MyInvisibleFunction ( List<int> Source )
{
    foreach ( int i in Source.Reverse() )
    {
       if ( i % 2 == 1 ) 
       {
           yield return i;
       } 
    }
} 

(Of course that's kind of a weird example because Source.Reverse() is itself a query, but anyways ...)

Now I'm confused where expression tress come into play here. When I think of expression trees, I think of trees like

        (3 % 1 > 0)
          /      \ 
         /        \   
     (3 % 1)  >    0
      /   \ 
     3  %  1

in the small world I've created. But where does a tree like that come in to play in my LINQ query

from i in All
where i % 2 == 1
orderby i descending
select i

??? That's what I don't understand. I'm looking at the Expression class and I see how it could create the example tree I showed, but I don't see where it would come into play in my query.

Upvotes: 0

Views: 335

Answers (2)

Eric Lippert
Eric Lippert

Reputation: 660058

I'll give you my best attempt at understanding it and you let me know where I'm going wrong.

OK.

What I understand first of all is that the query itself does not create a Ienumerable<int>;

This statement is completely wrong.

it creates and Expression Tree associated with the query.

This statement is also completely wrong.

The elements returned by the query are yielded in an invisible function created by the compiler

This statement is also completely wrong.

where does a tree like that come in to play in my LINQ query

It doesn't. Your query uses no expression trees.

I'm looking at the Expression class and I see how it could create the example tree I showed, but I don't see where it would come into play

It doesn't.

want to dissamble what happens when I do

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = from i in All
                        where i % 2 == 1
                        orderby i descending
                        select i; 
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

Let's break it down. First the compiler turns that into

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = All.Where(i => i % 2 == 1).OrderBy(i => i);                          
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

Next the compiler does overload resolution and evaluates extension methods

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = 
  Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, i => i % 2 == 1)), 
    i => i));                           
foreach ( var i in Filtererd ) 
  Console.WriteLine(i);

Next lambdas are desugared:

static bool A1(int i) { return i % 2 == 1; )
static int A2(int i) { return i }
...
List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered = 
  Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, new Func<int, bool>(A1))), 
    new Func<int, int>(A2)));                           
foreach (var i in Filtererd ) 
  Console.WriteLine(i);

That is actually not how the lambdas are desugared exactly; they are also cached, but let's ignore that detail.

I assume that you do not want the foreach desugared. See the C# specification for details.

If you want to know what Where and OrderBy do, read the source code.

Upvotes: 8

usr
usr

Reputation: 171178

Expression trees don't come into play in your query, because your source is a regular in-memory list. – Theodoros Chatzigiannakis

This is true.

There is no invisible iterator function being generated. Your query translates to:

List<int> All = new List<int> { 1, 2, 3, 4, 5 };
IEnumerable<int> Filtered =
 All
 .Where(i => i % 2 == 0)
 .OrderByDescending(i => i);

There is no need for custom iterators. The language just calls the existing library functions.

This is the same for IQueryable except that the lambda arguments are not passed as delegates but as expression trees.

You can see this in action by commenting in the AsQueryable() call here.

Upvotes: 1

Related Questions