Let first take a prediction, what is the result of the following code.
public static void ClosureForeachWithLambda()
{
var action = new List<Action>();
var list = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var i in list)
{
action.Add(() => Console.WriteLine(i));
}
foreach (var i in action)
{
i();
}
}
It is not 1..9 printed each once, instead it is the 9 printed 9 times. Not belieing, huh, trying it yourself.
So, let me post a complete code with comments to tell why this is happening. Also, in my code below, you will see a fix to the bug in .net 4. 0
public static void Main(string[] args)
{
ClosureForeachWithLambdaGotha();
}
public static void ClosureForeachWithLambda()
{
// the reason why this is a potential pitfall is because
// closure is not creating a copy, not copying the value, but instead it is
// the variable itself.
// but inside theo foreach loop,
// it is loop variable that is bound to and the bound is updated in each loop
// so at last, you will see that it is '9' that is printed 9 times
var action = new List<Action>();
var list = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var i in list)
{
action.Add(() => Console.WriteLine(i));
}
foreach (var i in action)
{
i();
}
}
public static void ClosureForeachWithLambdaGotha()
{
// a fix is to explicitly create a local variable,
// by which it is the variable in new scope that is closured
// here shows how:
//
// fortunately thi is going to be fixed in .net 4.5
// however, the bad news is that since 4.5 is going to be a inplace change.
// so that means it is going to be a breaking change.
var action = new List<Action>();
var list = new [] { 1,2 ,3, 4, 5, 6, 7, 8, 9};
foreach (var i in list)
{
var copy = i;
action.Add(() => Console.WriteLine(copy));
}
foreach (var i in action)
{
i();
}
}
As explained in the post : Lifting Foreach, Breaking change in Visual Studio 2012. It is going to be a breaking change, as the .net 4.5 is going to be a in place patch .
C# Lambda陷阱与修复
252

被折叠的 条评论
为什么被折叠?



