One of the stumbling blocks on the road to understanding LINQ is deferred execution. The key to getting past this is being able to identify that a query is a definition of what you want, rather than the results themselves.
Here’s an example of how this works:
1 2 3 4 5 6 7 8 9 |
|
The second time itemsInStock.Count()
is called it returns the updated count
that includes our new item. Instead of executing the query when it is defined,
execution is deferred until a result is needed (such as iterating over the
collection with a foreach
loop, using ToList()
to store the results in a
List<T>
or one of the many LINQ extension methods that force an actual
result (such as Count()
in this example). This has the added benefit of
allowing a query to be extended like so:
1 2 3 |
|
This query can now be used to return items that are in stock, but have less than 5 available units.
Quite often you’ll want to work with a snapshot of the results from a query. Maybe you are writing a method that returns a particular set of items. In this scenario it may be better to return a list rather than the query itself. By returning a list, the calling code is able to iterate over the result multiple times without the result changing. For example you might implement your method like this:
1 2 3 4 5 6 7 8 9 10 |
|
Calling code is able to get the information it needs and internally you can directly get access to the query.
Another important thing to remember is that because a query is executed every
time you iterate it with a foreach
loop you should use ToList()
if you are
repeatedly calling the query and don’t need the results to be recalculated
each time.
More LINQ to come
In my next post I’ll explore lambda expressions.