Hello Friends, In my previous article I have discussed about the different ways we can write LINQ queries in C#. I talked about the Lambda Syntax and comprehension syntax. In this article I want to discuss one important concept of LINQ queries known as deferred execution which can help you to prevent from making silly mistakes.
Deffered execution in LINQ
LINQ queries are not evaluated the moment when we apply conditions or constructed. Instead they are executed when the result is enumerated or when MoveNext() method is called on the results.
Let’s see an example for the same.
IList<string> names = new List<string> {"Vikram", "Prasad", "Nikhil", "Sumit", "Varun" }; var filteredNames = from name in names where name.StartsWith("V") select name; names.Add("Vijay"); Console.WriteLine(filteredNames.Count());
The result of the above code would be 3. As the foreach for the filteredNames collection would not be called when we apply LINQ queries on the sequence.
In other words enumeration of sequence does not takes place when filtering or sorting applied.
This is know as deffered or lazy evaluation of the sequence. All standard query operators provide deffered evaluation except:
- operators that return a single element or scalar value such as first or count.
- When you apply ToArray, ToList, ToDictionary, ToLookup operators on the result sequence.
One reason the above operators does not support deffered execution is that their result types does not support enumeration.
For example Count() returns a single digit which cannot be enumerated.
Deffered execution is important because it decouples query construction from query execution. This allows you to make a query in several steps.
Reevaluation in LINQ
Every time a sequence obtained after filtering or sorting of the original sequence is enumerated, the original sequence is considered again.
Lets see an example of the same.
public static void QueryOperator() { IList<string> names = new List<string> {"Vikram", "Prasad", "Nikhil", "Sumit", "Varun" }; var filteredNames = from name in names where name.StartsWith("V") select name; Console.WriteLine(filteredNames.Count()); names.Clear(); Console.WriteLine(filteredNames.Count()); Console.Read(); }
What do you think the result of the above method.
Reevaluation in LINQ can be troublesome and can cause some serious issues.
- If you want to cache the results of sorting and filtering, reevaluation will prevent you to do the same.
- If you are working on some huge data collection or retrieving data from external data source, reevaluation can consume lots of memory.
One way to prevent from reevaluation is to call the ToArray() or ToList() on the result sequence.
IList<string> names = new List<string> {"Vikram", "Prasad", "Nikhil", "Sumit", "Varun" }; var filteredNames = (from name in names where name.StartsWith("V") select name).ToArray(); Console.WriteLine(filteredNames.Count()); names.Clear(); Console.WriteLine(filteredNames.Count()); Console.Read();
And the result would be 2 for both of the above conditions.
I hope this article will help you to understand working of LINQ queries in .NET framework.
Leave a Reply