LINQ Deferred Execution–Oops!

A LINQ Tutorial

Deferred execution can be a lifesaver with LINQ but it can have a downside as well.

In this example we set up a LINQ query and then iterate through the results twice. The output may not be quite what we anticipated or want,

int counter = 0;
var evenNumbersInSeries = 
    Enumerable.Range(0, 10).Select(
    x => 
    {
       int result = x + counter;
       counter++;
       return result;
    }
    );

// List the numbers in the series

Console.WriteLine("First Try:\n");
foreach(int i in evenNumbersInSeries) 
{
    Console.WriteLine(i);
}

// List them again

Console.WriteLine("\nSecond Try:\n");
foreach(int i in evenNumbersInSeries) 
{
    Console.WriteLine(i);
}

 

The output for these two runs is shown in the two columns below:

0    10
2    12
4    14
6    16
8    18
10   20
12   22
14   24
16   26
18   28

 

Oops.  The Counter maintained its state, and since we don’t evaluate until the foreach loop, nothing causes the counter to reset.

We could solve this problem in two ways. One is to reset the counter before running the second loop. Another way to solve this is to freeze the evaluation by asking LINQ to convert the results (currently in the variable evenNumberInSeries to an array. The result would be that the entire series would be evaluated and placed in the array and then we’d iterate through the array:

int counter = 0;
var evenNumbersInSeries = 
    Enumerable.Range(0, 10).Select(
    x => 
    {
       int result = x + counter;
       counter++;
       return result;
    }
    ).ToArray();


Console.WriteLine("First Try:\n");
foreach(int i in evenNumbersInSeries) 
{
    Console.WriteLine(i);
}


Console.WriteLine("\nSecond Try:\n");
foreach(int i in evenNumbersInSeries) 
{
    Console.WriteLine(i);
}

 

Because ToArray forces the results into an array, the entire series is evaluated before the foreach loops run, and the foreach loops iterate over the array. The array has the (unchanging) results and so the two itereations are identical,

0   0
2   2
4   4
6   6
8   8
10  10
12  12
14  14
16  16
18  18

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, Linq, Mini-Tutorial and tagged . Bookmark the permalink.