2012-01-23 184 views
4

由於以下問題,我正在撕掉我的頭髮。我有這樣的代碼循環遍歷一個對象列表併爲它們中的每一個創建一個處理任務。System.Threading.Tasks for for循環問題

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

正如你所看到的,問題是,任務似乎都有一個對象的引用!

爲什麼這些任務都只使用列表中的一個對象?

感謝您幫助

回答

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

要了解更多:

The foreach identifier and closures

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

+0

這解決了這個問題!感謝您的快速響應 – GETah

4

object36963566必須是最後一個實例在你的瓷磚列表

這是因爲如何foreach作品目前執行的。淨。雖然將來會修復。

您需要閱讀Closing over the loop variable considered harmful以瞭解foreach在這種情況下的工作原理。

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

在上面的代碼info所指的是一個項目列表中的tiles。您正在創建的delegate將不會使用該項目info指的是創建它時(委託)。相反,它將使用當前值info(信息指向實際運行方法/委託時的值),該值顯然指向列表的最後一項。這就是爲什麼你得到這種行爲

+0

+1 – GETah