Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this LINQ query not executed when using foreach?

When creating new objects in a LINQ statement, for example:

var list = new List<string>() { "a", "b", "c" };
var created = from i in list select new A();

With class A looking like this:

class A
{
    public string Label;
}

And then modifying properties in A with a foreach loop:

foreach (var c in created) {
    c.Label = "Set";
}

Why are the values not set when accessing the objects in the IEnumerable afterwards. E.g. the following assertion fails:

Assert.AreEqual("Set", created.ElementAt(2).Label);

I wonder why this happens. I would expect the foreach-statement to execute the query, and trigger the creation of the objects. MSDN documentation states: "Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop".

I have reproduced this behavior with .NET 4.5 and Mono 3.2.0. Calling ToList on the IEnumerable before accessing the created object makes this problem go away.

like image 849
Stephan Palmer Avatar asked Sep 20 '13 12:09

Stephan Palmer


1 Answers

It's happening because created is a query, not a result. So, every time you enumerate it, you're evaluating the Select over again from scratch.

If you want this to work, make created an actual list, rather than just an IEnumerable representing a query.

For example, add:

created = created.ToList();

You say:

I would expect the foreach-statement to execute the query, and trigger the creation of the objects

This is exactly what is happening. The problem is the creation of the objects happens every time you iterate over created, not just the first time. Since the ElementAt() method iterates over created, it's just creating new As again.

like image 193
RobSiklos Avatar answered Oct 06 '22 23:10

RobSiklos