Reputation: 38154
I have a list of integer values;
var items= new List<int>();
items.Add(1);
items.Add(8);
items.Add(14);
items.Add(11);
var sequel=from i in items where i >10 select i;
items[1]=25;
Foreach(var c in sequel)
Console.WriteLine(c);
Output is 25 14 11
In my view the output should be 14, 11. However, the output is in fact 25, 14, 11.
My question is why compilator updating "sequel" after execution this statement "items[1]=25;"? In my view these collections are different and not connected. Please clarify.
UPDATE:
Yeah, I read about deferred execution and my first thought was that it is indeed. However, in debug mode, I've seen that sequel is "14, 11" before the statement:
items[1]=25;
Then, after this statement "sequel" becomes "25, 14, 11". So why does a compilator remake the query?
Upvotes: 0
Views: 282
Reputation: 101701
Because LINQ
uses deferred execution. This means that here:
from i in items where i >10 select i;
You are just constructing the query. It doesn't get executed unless you iterate over result using foreach
or use methods that iterates the query such as ToList
and ToArray
.That is why when you change the items, the query runs on the changed version.
For more info about deferred execution and lazy loading refer to the articles below:
UPDATE: In Debug
mode you are actually evaluating the query to see the results.This happens before you change the items.sequel
doesn't hold any numbers, it's just a query.Nothing else, you can only store numbers into a collection such as List
, the thing you see in debugger is just a feature that allows you to evaluate query immediately and shows you the results.
Upvotes: 3
Reputation: 21
It is because of Lazy Evaluation in LINQ. It's called "Deferred Execution" and means that condition will be apply to items
only when it will be iterated by foreach
loop.
Your sequel
varible has WhereListIterator
type. So if you want to Immediate Execution you just need to iterate this query by ToList()
or ToArray()
like this:
var sequel = (from i in items where i > 10 select i).ToList();
Your sequel
varible will get List
type and you could set it item value by:
sequel[1] = 25;
In output you will get 14 and 25 numbers.
Changing of items
won't affect to sequel
because it's different collection of value type objects.
Upvotes: 1
Reputation: 21815
This is known as Deferred execution
in LINQ. According to MSDN:-
The immediate return value is an object that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach
So to get the required output you need to materialize your query by using a ToList()
or ToArray
like this:-
var sequel=(from i in items where i >10 select i).ToList();
Update:
Okay agree, you must have seen the results in debug mode through Results View
right? So just check the description given with it, Visual Studio says:
Expanding the results will enumerate the IEnumarable
So just for viewing purpose in debug mode it enumerates and not in actual.
Upvotes: 2
Reputation: 3483
LINQ has so called deferred execution, which means it loads the data as needed, in your case on the Foreach.
See it like this: If you write an SQL-Statement, but not execute it, it won't do anything with the data. This is exactly the same.
More Infos, see here: http://www.codeproject.com/Articles/692847/THREE-Examples-of-Deferred-vs-I
Upvotes: 0
Reputation: 109732
Linq iterates over an existing collection - it does not make a copy of that collection. If the contents of that collection changes, the items in the iteration will change.
Also, Linq uses a "Deferred Execution" model, where the items in the collection are only visited when you iterate over the IEnumerable provided by Linq.
If you want to make a copy of the collection you can do it explicitly, like so:
var sequel=(from i in items where i >10 select i).ToArray();
You could also use .ToList()
.
Upvotes: 1