THREE examples of Deferred vs. Immediate execution in LINQ using C#

In DOT NET world we have Language-Integrated Query (LINQ) – it extends powerful query capabilities to the language syntax of C# and Visual Basic.

LINQ provider assemblies enable the use of LINQ with .NET Framework collections, SQL Server databases, ADO.NET Datasets, and XML documents. They are part of .NET framework 3.5 and above.

Now let’s see three ways to understand what exactly is this deferred and immediate execution all about in LINQ using C#.

DateTime to verify deferred execution of LINQ query

  • Create  console application with name “LinqSample
  • Create Product class with ID, Name, InStock members in it.
  • Create collection of products, LINQ Query and iterate through it to display time.
linq

Creating PRODUCT class and it’s sample collection

  • Now we will be creating two simple LINQ queries which will act as deferred and immediate query
linq

Queries to use for deferred and Immediate execution

We have created list of products, written query for deferred and immediate execution, now let’s loop through them in 3 different foreach loops to check difference in time they are executed.

The yellow lines indicate that once the immediate query gets executed, any subsequent looping will fetch same copy. While deferred execution gets executed for every loop showing different time stamp.

linq

Console output showing time stamp for Deferred & Immediate query execution

Collection Items update to show deferred execution & Immediate execution

Adding the items to collection in execution and looping them again is also easiest way to check when LINQ query executed.

We have to write a query which gets only In Stock products, loop through that query, add one more item to collection and loop through again. Below code snippet image clearly shows this.

linq

Code snippet showing additional product gets added to collection after query formed for Deferred execution

This code snippet below shows that we are doing same thing except converting result to TOLIST along with query.

linq

Code snippet showing additional product gets added to collection after query formed in Immediate execution

Now let’s compare both results after running the console application. Milk product added later is shown in deferred execution only. This is shown as yellow lines in screen shot.

linq

Deferred execution shows that even if collection changes, looping always result in fresh data

Is ToList() only way to force immediate execution?

No, it’s one of many methods that forces immediate execution. Here is the extract from MSDN on Immediate query execution

In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. Some examples of singleton queries are Average, Count, First, and Max. These execute immediately because the query must produce a sequence to calculate the singleton result. You can also force immediate execution. This is useful when you want to cache the results of a query. To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable.

Debugging LINQ query to show deferred & Immediate execution

Let’s use the above queries to debug console application. This is animated GIF to show debugging process.

linq

Animated gif file to show debugging steps of LINQ query

Let me summaries what is happening while debugging

At first break point

  • Deferred query is formed; it’s not executed as we can see that it only shows WhereSelectListIterator.
  • With help of F11 key, am “Step Into” debugging; at first for each loop, the execution pointer going to where condition in query “where d.InStock == true”.
  • It does same looping, checking where condition for all items in product list and keeps them displaying on the console.

At second break point

  • Immediate query is formed with ToLIST(), it immediate shows count as 5 before looping into for each loop.
  • Even when it’s iterating through for each loop, execution pointer never goes to where condition in query. It just prints out selected product on console.

In C#, the deferred execution is supported by directly using the yield keyword within the related iterator block. Below Table lists the iterators in C# that use the yield keyword to ensure the deferred execution.

MethodIterator
CastCastIterator
ConcatConcatIterator
DefaultIfEmptyDefaultIfEmptyIterator
DistinctDistinctIterator
ExceptExceptIterator
GroupJoinGroupJoinIterator
IntersectIntersectIterator
JoinJoinIterator
OfTypeOfTypeIterator
RangeRangeIterator
RepeatRepeatIterator
ReverseReverseIterator
SelectSelectIterator
SelectManySelectManyIterator
SkipSkipIterator
SkipWhileSkipWhileIterator
TakeTakeIterator
TakeWhileTakeWhileIterator
UnionUnionIterator
WhereWhereIterator
ZipZipIterator

Happy Coding with LINQ !!

Leave a Reply