i-think Twenty-Two

Now with more coherency.

LINQ and Deferred Execution

| Comments

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
var itemsInStock = from item in warehouse.Items
                   where item.Quantity > 0;
                   select item;
// Display how many items are in stock
Console.WriteLine("Items in stock: {0}", itemsInStock.Count());
// Add a new item to the warehouse
warehouse.Items.Add(new Item("A new item", 50);
// Display how many items are in stock
Console.WriteLine("Items in stock: {0}", itemsInStock.Count());

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
var lowStock = from item in itemsInStock
               where item.Quantity < 5;
               select item;

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
private IEnumerable<Item> GetItemsInStockQuery()
{
   return from item in warehouse.Items
          where item.Quantity > 0
          select item;
}
public List<Item> GetItemsInStock()
{
   return GetItemsInStockQuery().ToList();
}

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.

Comments