C# Parallel.Invoke执行Action列表时所有调用参数均为10问题排查
问题原因
该问题是C#中典型的循环变量闭包捕获问题,核心逻辑如下:
- for循环中定义的迭代变量
i的作用域覆盖整个循环周期,所有迭代全程复用同一个变量实例 - 代码中Lambda表达式
() => DoSomething(i)捕获的是i的引用,而非定义Lambda那一刻i的瞬时值 - 循环完全执行结束后
i的值已经迭代为10,后续Parallel.Invoke执行所有Lambda时,读取的都是这个已经变为10的同一个变量,因此所有调用的参数都是10
解决方法
在循环内部新增一个局部临时变量,存储当前迭代的i值,让Lambda捕获这个临时变量即可。每次迭代都会生成独立的临时变量实例,不会被后续迭代修改:
public static void Main() { var actions = new List<Action>(); for (int i = 0; i < 10; i++) { // 每次迭代创建独立的局部变量,Lambda捕获该变量不会被后续迭代覆盖 int currentNum = i; actions.Add(() => DoSomething(currentNum)); } Parallel.Invoke(actions.ToArray()); } private static void DoSomething(int number) { Console.WriteLine(string.Format("DoSomething number {0}", number)); Thread.Sleep(5000); }
补充说明:C# 5.0及以上版本已经优化了foreach循环的迭代变量捕获逻辑,foreach场景不会出现该问题,但for循环的逻辑未做调整,开发时需要注意规避该坑。
内容的提问来源于stack exchange,提问作者user3607621
相关产品推荐
相关产品推荐

