A while a go, the C# community got surprised by another GOTCHA, discovering that using a foreach iteration variable inside a LINQ query, may not always yield the expected results. The variable gets captured by the foreach loop and, due to the evil work of closure, it remains scoped outside of the LINQ query itself living its own life so to speak. This has now been corrected in the Visual Studio 11 Beta.

Consider a simple example. Let’s start with a very basic Team class. Here it is.

C#

1

2

3

4

5

publicclassTeam

{

publicstringname{get;set;}

publicTeam(stringn){name=n;}

}

Ok, now let’s take a generic list of our Team objects. We’ll also need an Enumerable to iterate through (in our case 4 iterations is enough ,as it corresponds to the List size), and a container for IEnumerable results of LINQ query we are gonna execute.

Alright, so far so good. Let’s loop through the Enumerable and use the iteration variable to select the Team from the collection and add it to the list container. Easy-peasy.

C#

1

2

3

4

5

6

7

8

foreach(varindex incount)

{

vart=from team inteams

where team.name==teams[index].name

select team.name;

teamsEnum.Add(t);

}

Now all we gotta do is just loop through the result list, and in there loop through IEnumerable and display the results.

C#

1

2

3

4

5

6

7

foreach(vartinteamsEnum)

{

foreach(varitem int)

Console.WriteLine(item);

Console.WriteLine();

}

Console.ReadLine();

This is definitely not rocket since, so it’s easy to predict the output.

Maple Leafs

Canadiens

Oilers

Senators

Right? Gotcha. Visual Studio 2010 produces this.

This problem lies in the foreach loop, which captured the iteration variable and kept changing it upon every iteration, thus affecting whatever we stored in the List<IEnumerable<string>>. A solution would be to introduce a new variable, copy the iteration’s variable value into it, and pass it to LINQ query instead.

Thankfully, this has been corrected in Visual Studio 11 Beta. Executing the same code in VS11b produces the following output, as expected.

So, if you have some old code that has been misbehaving, or you needed to copy variables inside the loop to avoid it, all you need to do now to resolve it is to recompile your code using VS11b.