LINQ – Deferred Query Evaluation

I have recently started reading Programming Microsoft LINQ. I am still in the first few chapters but came across a aspect of LINQ that could cause a frustrating bug in a developer’s code. I have not used LINQ that much in my day to day development so I have not had a bug caused by this aspect. Deferred Query Evaluation is the aspect that I am talking about. This refers to the fact that LINQ queries aren’t executed until they are user.

Let’s take a look at an example. I have a Person class defined as the following:

   1:  public class Person   
   2:  {   
   3:          public string FirstName { get; set; }   
   4:          public string LastName { get; set; }   
   5:          public int Age { get; set; }   
   6:  }

Here is a simple LINQ query:

   1:  static void Main(string[] args)   
   2:  {   
   3:              List<Person> people = new List<Person>();   
   4:     
   5:              people.Add(   
   6:                  new Person   
   7:                  {   
   8:                      FirstName = "Joe",   
   9:                      LastName = "Smith",  
  10:                      Age = 30  
  11:                  });  
  12:    
  13:              people.Add(  
  14:                  new Person  
  15:                  {  
  16:                      FirstName = "Jane",  
  17:                      LastName = "Doe",  
  18:                      Age = 28  
  19:                  });  
  20:    
  21:              people.Add(  
  22:                  new Person  
  23:                  {  
  24:                      FirstName = "William",  
  25:                      LastName = "Jones",  
  26:                      Age = 65  
  27:                  });  
  28:    
  29:              var query = from p in people  
  30:                          select p;            
  31:    
  32:              Console.WriteLine("There are {0} people in my list.",  
  33:                  query.Count());  
  34:          }

With deferred execution the query is not executed until line 33. This is easy to prove, the previous code outputs that there are 3 people in the list. If I insert the follow code into line 31 I will get 4 people in the list:

   1:             people.Add(   
   2:                  new Person   
   3:                  {   
   4:                      FirstName = "Adam",   
   5:                      LastName = "West",   
   6:                      Age = 53   
   7:                  });

Another aspect of deferred execution is that it is evaluated each time the query is used so if I add another person to the list after the Console.WriteLine and executed the same WriteLine code after that, I would get 5 people in the list. This allows me to create my query and use it multiple times, even if my collection changes.

So how can this cause a bug? The first thing I though about when i read about deferred query execution is what happens if a developer does not know about deferred execution. They may not expect the results of the query to be changed by modifications made to the collection after defining the query or even after its first run. If the developer needs a copy of the results at a specific point in time, they should call the ToList, ToArray or other functions that the query exposes.

   1:  List<Person> people2 = query.ToList<Person>();

This is a minor aspect but one that can come back and haunt a developer if they don’t understand the LINQ framework.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Create a website or blog at WordPress.com

Up ↑

%d bloggers like this: