Deferred Execution
An important feature of most query operators is that they execute
not when constructed, but when enumerated (in other
words, when MoveNext
is called on its
enumerator). Consider the following query:
var numbers = new List<int>( ); numbers.Add (1); // Build query IEnumerable<int> query = numbers.Select (n => n * 10); numbers.Add (2); // Sneak in an extra element foreach (int n in query) Console.Write (n + "|"); // 10|20|
The extra number that we sneaked into the list
after constructing the query is included in the
result because it’s not until the foreach
statement runs that any filtering or
sorting takes place. This is called deferred or
lazy evaluation. All standard query operators
provide deferred execution, with the following exceptions:
Operators that return a single element or scalar value, such as
First
orCount
The following conversion operators:
ToArray, ToList, ToDictionary, ToLookup
These operators cause immediate query execution because their
result types have no mechanism for providing deferred execution. The
Count
method, for instance, returns a
simple integer, which doesn’t then get enumerated. The following query
is executed immediately:
int matches = numbers.Where (n => n <2).Count(); // 1
Deferred execution is important because it decouples query construction from query execution. This allows you to construct a query in several steps, and it makes LINQ to SQL queries possible.
Note
Subqueries provide another level of indirection. Everything in a subquery ...
Get LINQ Pocket Reference now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.