由于以下问题,我正在撕掉我的头发。我有一些代码循环遍历对象列表并为每个对象创建一个处理任务。
IList<TileInfo> tiles = tileSource.Schema.GetTilesInView(extent, level);
List<Task> renderingTasks = new List<Task>();
foreach (TileInfo info in tiles) {
renderingTasks.Add(Task.Factory.StartNew(new Action(delegate {
Console.WriteLine(Task.CurrentId +"Info object"+ info.GetHashCode());
}
})));
}
此代码打印:
1Info object36963566
2Info object36963566
3Info object36963566
4Info object36963566
5Info object36963566
6Info object36963566
7Info object36963566
8Info object36963566
9Info object36963566
10Info object36963566
11Info object36963566
12Info object36963566
...
正如您所看到的,问题是任务似乎都引用了一个对象!
为什么这些任务都只使用列表中的一个对象?
谢谢你的帮助
答案 0 :(得分:5)
我会尝试在一瞬间添加更多细节,但这是关闭变量。将代码更改为:
基本上你需要做的是在循环中创建一个新变量,等于循环内部工作之外的单个声明。
IList<TileInfo> tiles = tileSource.Schema.GetTilesInView(extent, level);
List<Task> renderingTasks = new List<Task>();
foreach (TileInfo info in tiles)
{
TileInfo closingInfo = info;
renderingTasks.Add(Task.Factory.StartNew(new Action(delegate {
Console.WriteLine(Task.CurrentId +"Info object"+ closingInfo.GetHashCode()); }})));
}
阅读更多内容:
答案 1 :(得分:4)
object36963566
必须是您的图块列表中的最后一个实例
这是因为foreach
在.Net的当前实现中的工作原理。虽然将来会修复。
您需要阅读Closing over the loop variable considered harmful以了解foreach在这种情况下的工作原理。
Task.CurrentId +"Info object"+ info.GetHashCode()
info
指的是列表tiles
中的项目。您创建的delegate
将不会使用info
所指的项目(委托)创建时间。相反,它将使用info
的当前值(信息在方法/委托实际运行时指向的值),这显然指向列表的最后一项。这就是你得到这种行为的原因