StepUp
StepUp

Reputation: 38154

Why is linq result updated, if a source is updated afterwards?

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

Answers (5)

Selman Gen&#231;
Selman Gen&#231;

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

Mike Kozhevnikov
Mike Kozhevnikov

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

Rahul Singh
Rahul Singh

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

Matthias M&#252;ller
Matthias M&#252;ller

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

Matthew Watson
Matthew Watson

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

Related Questions