C# lambda and foreach variable
Posted by Bojan Resnik on June 17, 2009
Can you guess what the output of the following program is?
using System;
using System.Collections.Generic;
namespace Lambda
{
class Program
{
static void Main(string[] args)
{
var strings = new[] {"a", "b", "c"};
var actions = CreateActions(strings);
actions.ForEach(f => f());
}
private static List<Action> CreateActions(IEnumerable<string> strings)
{
var actions = new List<Action>();
foreach (var s in strings)
actions.Add( () => Console.WriteLine(s) );
return actions;
}
}
}
I expected to see all three strings (a, b and c), but instead I got this:

While analyzing the IL code with Reflector I learned a thing or two about lambdas in C#.
When a lambda is encountered by the compiler, it generates a class which has a field for each local variable used by the lambda. In this case, the generated class would look like this in C#:
private sealed class <>c_DisplayClass3
{
public string s;
public void <Main>b_0()
{ Console.WriteLine(this.s); }
}
Of course, the above is not valid C# due to invalid characters in identifiers, but is pretty much what is produced in the IL.
So far so good – no real surprises here. However, look at this code which is my translation from IL to C# of the CreateActions method:
private static List<Action> CreateActions(IEnumerable<string> strings)
{
List<Action> actions = new List<Action>();
using (IEnumerator<string> enumerator = strings.GetEnumerator())
{
// Note 1: The lambda is created outside of the loop
<>c_DisplayClass3 lambda = new <>c_DisplayClass3();
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
// Note 2: The instance field is reassigned each time
lambda.s = s;
actions.Add(lambda);
}
}
return actions;
}
The reason for the strange output is clear now – the compiler did not create a lambda object in each iteration but rather reused the existing one each time. After the loop, all items in the actions list are actually the same instance and their s field is the last element of the collection. Apparently, C# compiler creates a lambda instance immediately before the local variable it uses. So, in order to force it to create a new lambda for each iteration, we need to introduce a new local variable in the loop:
private static List<Action> CreateActions(IEnumerable<string> strings)
{
var actions = new List<Action>();
foreach (var s in strings)
{
// This variable will be used in the lambda
var lambda_param = s;
actions.Add( () => Console.WriteLine(lambda_param) );
}
return actions;
}
With this modification the program now produces this output:

Flash said
Great post!
Tormod said
Nice and precise. Informative. Not only regarding Lambdas, but also how the transparency offered by the occasional C# to IL to C# dive is an essential skill that at least should be somewhere in the development team.
Tormod said
After looking a bit more, I realize that the loop returns exactly what is expected. A lambda performed on an “s” reference, which changes before the lambda is actually executed, should not behave any differently.
DotNetBurner - C# said
C# lambda and foreach variable…
DotNetBurner – burning hot .net content…
Jason Young said
That is really odd. Can anyone explain WHY it works this way? That doesn’t seem intuitive or easily recognizable.
Jeff Becker said
Because a closure captures the variable, not the value.
Bojan Resnik said
Before exploring this, I expected the compiler to create a new lambda object each time it encouters a lambda definition. However, I guess that for the typical usage of lambdas this would be just a waste of time and space.
CodeThinked | Reflecting Code Is Not A Perfect Science said
[...] All this time though, I knew that there would be some very interesting translations and manipulations that occurred, but I didn’t really consider that the code which reflector spit out might not actually execute in the same way as the code that I was compiling. Well, today I found just that case (in the latest version of Reflector) while checking out this blog post. [...]
Weekly Link Post 107 « Rhonda Tipton’s WebLog said
[...] C# lambda and foreach variable [...]
Thorn said
As usual, M$ “tricks” leads to ugly code style, named ‘Microsoft experience’.
Who cares your damn ‘effectiveness’ when you produce really wrong code? As M$ promises, “JIT” must eliminate all bottlenecks, giving optimized, native code. So why you make your own optimizations?