1. Computing & Technology

Discuss in my forum

LINQ Queries - Deferred Queries

What is a Deferred Query?

By , About.com Guide

Updated January 16, 2012

The heart of the technology introduced with LINQ is called query expressions. I wrote the article LINQ Queries that introduced these queries using an array of words from a famous quote from American history, Thomas Paine's The Crisis):

 "These are the times that try men's souls!" 

The final example in that article shows how the words can be easily sorted. (code below) And the result is almost an even more profound question:

are men's souls! that the These times try

If not for that extra 'the' in there to make it ungrammatical, this would be an interesting question itself. This article will illustrate the concept of "deferred queries" that is an inherent part of most LINQ queries by showing a 'before and after' example with 'the' removed in the 'after' example.

Here's the complete 'before' code for the query. To code this yourself, drop this into the Click event for a button.

 ' This just sets up the array
 Dim Words As String = "These are the times that try men's souls!"
 Dim WordArray() As String = Split(Words)
 ' This defines the sequence of words returned by the query
 Dim Sequence As IEnumerable(Of String) = _
    WordArray.OrderBy(Function(n) n)
 ' This enumerates the query
 For Each Name As String In Sequence
    Console.Write(Name & " ")
 Next 

One might think that the Sequence collection is created in the statement:

 Dim Sequence As IEnumerable(Of String) = _
    WordArray.OrderBy(Function(n) n) 

It's not, however. Technically, only the query is stored in Sequence. The query is actually performed - that is, the sort against the original collection, WordArray - when it is enumerated in the For-Each loop. Misunderstanding this critical bit of processing can be the source of devilish bugs. To demonstrate this, let's get rid of that troublesome 'the' in WordArray and simply execute the same loop again. (Add this code in the same Click event after the code above. I added a question mark at the end just to make the result look better.)

 ' Get rid of 'the' in the array
 WordArray(2) = ""
 ' Enumerate the array again
 For Each Name As String In Sequence
    Console.Write(Name & " ")
 Next
 Console.Write("?") 

The Sequence collection is not changed. Only the source, WordArray is changed. But the result is different anyway.

are men's souls! that These times try ?

That's what a "deferred LINQ query" is. The query is only executed when it's enumerated, not when it's defined.

To make matters more confusing, some LINQ queries are deferred and some are not. All of the Aggregate queries, for example, are not deferred. These return a single value so they're not enumerated. This example shows that when the original WordArray is changed, the answer stays the same this time.

 ' This just sets up the array
 Dim Words As String = "These are the times that try men's souls!"
 Dim WordArray() As String = Split(Words)
 ' This defines the an aggregate query on WordArray
 Dim ArrayCount As Integer = WordArray.Count(Function(n) True)
 Console.WriteLine(ArrayCount)
 Console.WriteLine(vbNewLine & "------------")
 ' Add another member of the array
 ReDim Preserve WordArray(UBound(WordArray) + 1)
 WordArray(UBound(WordArray)) = "Whatever"
 ' The Array is not counted again, the orginal count is still used
 Console.WriteLine(ArrayCount) 

Microsoft's documentation on this point is a bit skimpy. I recommend Chapter 3 of Pro LINQ - Language Integrated Query in VB 2008 instead.

©2012 About.com. All rights reserved.

A part of The New York Times Company.