我遇到了一个关于 C# 的有趣问题。我有如下代码。列表
我遇到了一个有关 C# 的有趣问题。我有如下代码。
List<Func<int>> actions = new List<Func<int>>();
int variable = 0;
while (variable < 5)
{
actions.Add(() => variable * 2);
++ variable;
}
foreach (var act in actions)
{
Console.WriteLine(act.Invoke());
}
我希望它输出 0、2、4、6、8。但是,它实际上输出了五个 10。
看起来这是因为所有操作都引用一个捕获的变量。因此,当它们被调用时,它们都有相同的输出。
有没有办法解决这个限制,让每个动作实例都有自己的捕获变量?
在幕后,编译器会生成一个代表方法调用闭包的类。它会在循环的每次迭代中使用该闭包类的单个实例。代码如下所示,这样可以更轻松地了解错误发生的原因:
void Main()
{
List<Func<int>> actions = new List<Func<int>>();
int variable = 0;
var closure = new CompilerGeneratedClosure();
Func<int> anonymousMethodAction = null;
while (closure.variable < 5)
{
if(anonymousMethodAction == null)
anonymousMethodAction = new Func<int>(closure.YourAnonymousMethod);
//we're re-adding the same function
actions.Add(anonymousMethodAction);
++closure.variable;
}
foreach (var act in actions)
{
Console.WriteLine(act.Invoke());
}
}
class CompilerGeneratedClosure
{
public int variable;
public int YourAnonymousMethod()
{
return this.variable * 2;
}
}
这实际上不是您的示例中编译的代码,但我检查了我自己的代码,它看起来非常像编译器实际生成的内容。