这个非常简单的例子:
int numLanes = 8;
var tasks = new List<Task>();
for (var i = 0; i < numLanes; ++i)
{
var t = new Task(() =>
{
Console.WriteLine($"Lane {i}");
});
tasks.Add(t);
}
tasks.ForEach((t) => t.Start());
Task.WaitAll(tasks.ToArray());
Run Code Online (Sandbox Code Playgroud)
产生:
Lane 8
Lane 8
Lane 8
Lane 8
Lane 8
Lane 8
Lane 8
Lane 8
Run Code Online (Sandbox Code Playgroud)
这与预期不同,参数i未正确传递。我曾想过用来Action<int>包装代码,但看不到我会怎么做。我不想写一个专门的方法,就像Task CreateTask(int i)我对如何使用 lambda 感兴趣一样。
执行此操作的正常方法是什么 - 使用不同的参数值并行地多次启动相同的代码?
您有一个捕获的循环变量i,尝试在循环内添加临时变量并将其传递给Task
for (var i = 0; i < numLanes; ++i)
{
var temp = i;
var t = new Task(() =>
{
Console.WriteLine($"Lane {temp}");
});
tasks.Add(t);
}
Run Code Online (Sandbox Code Playgroud)
进一步阅读如何在 C# 中捕获变量而不是用脚射击自己。foreach循环在 C# 5 之前具有相同的行为,但根据上面的链接
随着 C# 5.0 标准的发布,通过在每次循环迭代中声明迭代器变量来改变这种行为,而不是在编译阶段之前,但对于所有其他结构,类似的行为保持不变,没有任何变化
因此,您可以在foreach没有临时变量的情况下使用
您需要捕获for循环内的值,否则所有的Tasks 仍然指的是同一个对象:
for (var i = 0; i < numLanes; ++i)
{
var innerI = I; // Copy the variable here
var t = new Task(() =>
{
Console.WriteLine($"Lane {innerI}");
});
tasks.Add(t);
}
Run Code Online (Sandbox Code Playgroud)
请参阅此处了解更多信息。