Reputation: 2887
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
1
, 2
, 3
, 4
, 5
%
, >
with their usual precdenceI 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 yield
ed 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
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
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