能否保证变量值传递至新Task?代码断言是否始终成立?
问题解答
你的代码中,index和attributesChunked的变量值都能被正确传递到Task.Run的lambda表达式中,不过代码存在几处问题,修正后断言才能稳定通过,具体分析如下:
1. 变量捕获的作用域说明
index变量:它是在foreach循环的每次迭代内部声明的,每次迭代都会生成一个独立的index实例。lambda表达式捕获的是当前迭代的这个实例,不会被后续迭代的变量覆盖,因此每个Task拿到的都是当前迭代对应的index值,不会出现混乱。这里用Interlocked.Increment更新共享的chunkIndex是安全的,因为最终结果会被存入当前迭代的独立index变量中。attributesChunked变量:在C# 5及以后的版本中,foreach的迭代变量是在每次迭代内部创建的新变量,而非共享同一个变量。因此每个Task的lambda捕获的都是当前迭代对应的chunk实例,不会出现多个Task共享同一个attributesChunked的问题。
2. 代码中的问题与修正
你的代码存在三处需要修正的地方:
- 断言字符串错误:数组中第一个元素是
"att1",但断言里写的是"attr1",不修正的话第一个断言会直接失败; - 逻辑错误:
attributes.Chunk(2)会将4个元素分成2个chunk,index的值只会是0和1,因此index == 2的条件永远不会触发,第二个断言永远不会执行,应改为index == 1; - 语法错误:
Task.Run的lambda表达式和tasks.Add的括号未闭合,无法编译。
修正后的代码如下:
var tasks = new List<Task>(); var attributes = new string[4]{ "att1", "att2", "att3", "att4" }; var chunkIndex = -1; foreach (var attributesChunked in attributes.Chunk(2)) { var index = Interlocked.Increment(ref chunkIndex); tasks.Add(Task.Run(() => { if (index == 0) Assert.Equal("att1", attributesChunked.First()); if (index == 1) Assert.Equal("att3", attributesChunked.First()); })); } await Task.WhenAll(tasks);
修正后,所有断言都能稳定通过,变量值的传递也完全符合预期。
内容的提问来源于stack exchange,提问作者Gary Brunton
相关产品推荐
相关产品推荐

