I wonder how LINQ to Objects determines the best way to query in a collection ?
I mean, is there any difference (in how LINQ works internally) between the following LINQ queries:
var lst1 = ListOfComplexClass.Where(p => p.StrValue == "Whatever")
.Select(p => p.StrValue);
And
var lst2 = ListOfComplexClass.Select(p => p.StrValue)
.Where(p => p == "Whatever");
For example, will the first one filter the collection of ListOfComplexClass and then get the StrValue property?
Or will it do some tuning and execute the Select first and then filter the returned collection?
(I am assuming that you meant
p => p.StrValuein theSelectin the first one.)Actually, it’s more subtle than that.
Let us say that you take an enumerator on the first one.
When you call
e.MoveNext(), what will happen is thatSelectwill callMoveNext()on an iterator ofListOfComplexClass.Where(p => p.StrValue == "Whatever")which will callMoveNext()an iterator ofListOfComplexClassuntil it finds an elementpwithp.StrValue == "Whatever". Then, the projected result of thispwill be returned ase.Current.Now let us consider the second one. Let us say that you take an enumerator of it.
When you call
e.MoveNext(),Wherewill callMoveNext()on an iterator ofListOfComplexClass.Select(p => p.StrValue)until it finds an elementpwithp == "Whatever". Of course, callingMoveNext()on an iterator ofListOfComplexClass.Select(p => p.StrValue)will callMoveNext()on an iterator ofListOfComplexClassand return the projection ofCurrentfor that iterator.Jon Skeet has a good analogy which I’ll steal here. Imagine a deck of cards in random order. Imagine the queries
and
Now imagine consuming the result of the first query. It goes like this.
SelectasksWherefor a card.Whereasksdeckfor a card.*
Wherechecks the suit of the card.If the suit of the card is a diamond or a heart, it returns the card to the
SelectandSelectprojects the card to its suit and returns it.If the suit of the card is not a diamond or a heart,
Whereasks for another card from deck and loops back to *.The second query goes like this.
WhereasksSelectfor a suit.Selectasksdeckfor a card.deckreturns a card to Select.Selectprojects the card to its suit.*
Wherechecks the suit from theSelect.If the suit is a diamond or a heart,
Wherereturns the suit.If the suit is not a diamond or a heart,
WhereasksSelectfor another suit and loops back to *.