Introduction
In the .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 look at 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.
Creating PRODUCT class and its sample collection
- Now we will be creating two simple LINQ queries which will act as deferred and immediate query
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 the same copy. While deferred execution gets executed for every loop showing different time stamp.
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. The below code snippet image clearly shows this:
Code snippet showing additional product gets added to collection after query formed for Deferred execution
This code snippet below shows that we are doing the same thing except converting result to TOLIST
along with query.
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.
Deferred execution shows that even if collection changes, looping always result in fresh data
Is ToList() the 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.
Animated GIF file to show debugging steps of LINQ query
Let me summarise 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 the 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 immediately shows count
as 5
before looping into foreach
loop. - Even when it’s iterating through
foreach
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. The below table lists the iterators in C# that use the yield
keyword to ensure the deferred execution.
Method | Iterator |
Cast | CastIterator |
Concat | ConcatIterator |
DefaultIfEmpty | DefaultIfEmptyIterator |
Distinct | DistinctIterator |
Except | ExceptIterator |
GroupJoin | GroupJoinIterator |
Intersect | IntersectIterator |
Join | JoinIterator |
OfType | OfTypeIterator |
Range | RangeIterator |
Repeat | RepeatIterator |
Reverse | ReverseIterator |
Select | SelectIterator |
SelectMany | SelectManyIterator |
Skip | SkipIterator |
SkipWhile | SkipWhileIterator |
Take | TakeIterator |
TakeWhile | TakeWhileIterator |
Union | UnionIterator |
Where | WhereIterator |
Zip | ZipIterator |
Happy coding with LINQ !!
CodeProject
The post THREE examples of Deferred vs. Immediate execution in LINQ using C# appeared first on Mithunvp.com.