Deferred Execution in LINQ

A LINQ Tutorial

As part of my on-going exploration of technologies related to programming Silverlight Doubler and Windows Phone, I’ve been exploring LINQ in some detail.

Today, I’d like to take a look at how LINQ queries are executed; specifically focusing on the delay in execution that makes LINQ so performant.

[Double click on image for full size]

To begin, divide your main page vertically into two equal columns, and add a ListBox to each column, as shown in the following Xaml,

<Grid
   x:Name="ContentPanel"
   Grid.Row="1"
   Margin="12,0,12,0">
   <Grid.ColumnDefinitions>
      <ColumnDefinition
         Width="1*" />
      <ColumnDefinition
         Width="1*" />
   </Grid.ColumnDefinitions>
   <ListBox
      Name="DeferredLB"
      Grid.Column="0"
      Margin="10"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch" />

   <ListBox
      Name="NotDeferredLB"
      Grid.Column="1"
      Margin="10"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch" />
</Grid>

To demonstrate that LINQ uses deferred execution, we’ll set up a query that relies on a method call.  Inside the method call, we can add to the ListBox so that we can see which method is running at any given moment.

 public MainPage( )
 {
    InitializeComponent( );
    int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 };

    var query =
    from prime in primes
    select Doubler( prime, DeferredLB );

    foreach ( var n in query )
       DeferredLB.Items.Add( n );
 }

 private static int Doubler( int n, ListBox lb )
 {
    lb.Items.Add( "Doubling " + n );
    n *= 2;
    return n;
 }

When you run this application, you see that control bounces back and forth from the query in Main to the Doubler method as each item is yielded in the enumerator that is implicitly called by the foreach loop.  The query is not executed until needed and if you were to cut off the query half way through then the remaining values would never load into memory.

To nail this down, let’s force the query to be executed all at once.  To do this, all we do is to convert the query to a list. This forces the query to execute in full (to populate the list) and then we can iterate through that list all in one go.  We’ll populate the right hand list box with the results of that approach:

 public MainPage( )
 {
    InitializeComponent( );
    int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 };

    var query =
    from prime in primes
    select Doubler( prime, DeferredLB );

    foreach ( var n in query )
       DeferredLB.Items.Add( n );

    query =
    from prime in primes
    select Doubler( prime, NotDeferredLB );

    foreach ( var n in query.ToList( ) )
       NotDeferredLB.Items.Add( n );
 }

The result is shown in the image at the top of this posting.

Note that we use an array and the compiler optimizes enumeration of arrays, but that does not affect the point made in this discussion.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Data, Essentials, Linq, Mini-Tutorial, WindowsPhone and tagged . Bookmark the permalink.

4 Responses to Deferred Execution in LINQ

Comments are closed.