Deferred Execution
There is one factor that you simply should understand before we tend to still future lessons. you want to understand that LINQ uses delayed execution once activity queries. This merely means the particular question isn’t dead till you tell over or access every worth from the result. think about the subsequent example:
int[] numbers = { 1, 2, 3, 4, 5 };
int i = 3;
var result = from n in numbers
where n <= i
select n;
i = 4;
foreach (var n in result)
{
Console.WriteLine(n);
}
Example 1
1 2 3 4
We haven’t looked at the where operator up to now so I will give a brief description of it for the sake of describing the deferred execution. The where operator is used to filter the results from a query based on a specified condition. On the code above, the whereoperator(line 6) instructs the query to only retrieve values which are less than or equal to whatever the value of i is. We will look at the where operator in more detail in a later lesson but for now, let’s concentrate on understanding the deferred execution.
You can see that 3 was assigned to i at line 3. Therefore, when the query expression in lines 5 to 7 executes, the where operator is comparing each item to 3 and if it is less than or equal to it, then they will be included in the result. You must be assuming now that the result variable contains values 1, 2, and 3, but actually, it only contains a computation on how you can get those values. Now in line 9, the value of i is modified by assigning it a value of 4. Because of deferred execution, this directly affects the result of the query expression in lines 5-7. I have said earlier that this query will only be executed once the program asks for the first item of the result and this can be done using a foreach loop. The foreach loop in lines 11-14 executes the query expression and returns the first item from the result of the query. Note that since we modified the value of i, then the query expression was updated as well. The foreach loop will show values from 1 to 4 instead of 1 to 3. This is one of the uses of deferred execution. The program is allowed to update the query expression before actually using or executing it to get values.
Deferred execution is just the default behavior of LINQ, but you can also make the execution of the query immediate. You can use another set of methods from the System.Linq namespace which compose of ToArray<T>(), ToList<T>(), ToDictionary<T>(), and ToLookUp<T>(). These are also extension methods for the IEnumerable<T> interface. For example, you can use the ToList<T>()method to convert the result of the query expression into a List<T> collection. Example 2 shows how we can use ToList() to immediately execute the query expression.
int[] numbers = { 1, 2, 3, 4, 5 };
int i = 3;
var result = (from n in numbers
where n <= i
select n).ToList();
i = 4;
foreach (var n in result)
{
Console.WriteLine(n);
}
Example 2
1 2 3
Since the query expression was immediately executed, once the program leaves line 7, the result variable already contains the results of the query. So even if we edit the value of i in line 9, the contents of the result is not changed. This can be seen by iterating each value using a foreach loop. The values shown will be 1 to 3 instead of 1 to 4.
Please note that deferred execution is not associated with the query expression itself but to the set of methods that those query expressions represent. It is the extension methods of the System.Linq namespace that tells whether the query will use deferred execution or not. For example, the Select() method uses deferred execution while the ToList() method uses immediate execution. For example, the query below uses the method syntax and the Select() method to query everything from an array.
var result = numbers.Select(n => n);
Since the Select() method uses deferred execution, this will not immediately execute until a foreach loop iterates every result. On the other hand, if you use a method using a deferred execution right after the Select() method, then execution of the methods will immediately take place.
var result = numbers.Select(n => n).ToList();
Whichever method is executed last determines whether the deferred execution will be used.
The following table shows the ways of System.Linq and tells whether or not career them can cause delayed execution.
Method | Execution | Method | Execution |
---|---|---|---|
Distinct | Deferred | Reverse | Deferred |
DefaultIfEmpty | Deferred | Select | Deferred |
ElementAt | Immediate | SelectMany | Deferred |
ElementAtOrDefault | Deferred | SequenceEqual | Immediate |
Except | Deferred | Single | Immediate |
First | Immediate | SingleOrDefault | Immediate |
FirstOrDefault | Immediate | Skip | Deferred |
GroupBy | Deferred | SkipWhile | Deferred |
GroupJoin | Deferred | Sum | Immediate |
Intersect | Deferred | Take | Deferred |
Join | Deferred | TakeWhile | Deferred |
Last | Immediate | ThenBy | Deferred |
LastOrDefault | Immediate | ThenByDescending | Deferred |
LongCount | Immediate | ToArray | Immediate |
Max | Immediate | ToDictionary | Immediate |
Min | Immediate | ToList | Immediate |
OfType | Deferred | ToLookup | Immediate |
OrderBy | Deferred | Union | Deferred |
OrderByDescending | Deferred | Where | Deferred |
Figure 1 – Methods Using Deferred Execution or Immediate Execution
If the table above is too hard to remember, then you can just remember one rule on determining whether a query is deferred. If a query is expected to return a single result such as a single number or object, then it will be immediately executed. When a query will return an IEnumerable<T> result, then most of the time it will use deferred execution. One strategy to check whether a question returns an IEnumerable<T>result is by floating over the var watchword of the inquiry articulation while you are in the Visual Studio editorial manager. Look whether the assistance bubble demonstrates that it is an IEnumerable<T> write. Assuming this is the case, at that point the question will utilize conceded execution.