C#中for循环添加Task全部输出6、foreach添加Task正常的原因求解
问题原因分析
核心是C#的闭包变量捕获规则在for和foreach循环中的表现不同导致的:
1. for循环输出全为6的原因
- for循环中声明的迭代变量
i,在整个循环生命周期内仅存在同一个实例,所有Task.Run传入的lambda表达式捕获的都是这同一个i变量,而非循环执行到对应位置时i的瞬时值。 Task.Run创建的任务不会立刻执行,会等待线程池调度。而for循环执行速度远快于任务调度速度,等循环退出时,i已经完成最后一次自增变成6(循环退出条件为i < 6不成立,此时i的值就是6),所有任务启动后读取到的i都已经是6,因此输出全为6。
2. foreach循环结果符合预期的原因
- C# 5.0及更高版本对foreach循环的捕获规则做了调整:每次循环迭代的
item变量都是全新的独立实例,每个lambda捕获的都是对应迭代专属的item变量,和其他迭代的item互不干扰。 - 因此就算任务延后执行,读取到的也是当前迭代对应数组元素的值,仅因任务调度顺序不固定,输出顺序和数组原始顺序不同,值都是正确的。
修复for循环问题的方案
在for循环体内声明临时变量存储当前迭代的i值,让lambda捕获这个临时变量即可:
var tasks = new List<Task>(); for (int i = 1; i < 6; i++) { // 每次迭代生成独立的临时变量,lambda捕获的是该次迭代的临时变量 var current = i; tasks.Add(Task.Run(() => Console.WriteLine(current))); } Task.WaitAll(tasks.ToArray());
内容的提问来源于stack exchange,提问作者kalka79
相关产品推荐
相关产品推荐

