for循环中的System.Threading.Tasks问题

本文关键字:Threading Tasks 问题 System 循环 for | 更新日期: 2023-09-27 18:21:04

由于以下问题,我要把头发扯掉了。我有一段代码,它循环遍历对象列表,并为每个对象创建一个处理任务。

        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
...

正如你所看到的,问题是任务似乎都引用了一个对象!

为什么所有任务都只使用列表中的一个对象?

感谢您对的帮助

for循环中的System.Threading.Tasks问题

我稍后会尝试添加更多细节,但这是关于结束变量的。将您的代码更改为:

从本质上讲,您需要做的是在循环内部创建一个新变量,等于循环内部工作之外的单个声明。

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()); }})));
}

阅读更多:

foreach标识符和闭包

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

object36963566必须是平铺列表中的最后一个实例

这是因为foreach在.Net的当前实现中是如何工作的。尽管它在未来会被修复。

对于理解foreach在这种情况下的工作方式,您需要阅读被认为有害的循环变量上的闭包。

Task.CurrentId +"Info object"+ info.GetHashCode()

上述代码中的CCD_ 4是指列表CCD_。您正在创建的delegate将不会使用创建(委托)时info所引用的项。相反,它将使用info的当前值(当方法/委托实际运行时,info所指向的值),该值显然指向列表的最后一项。这就是为什么你会得到这种行为