2012-10-15 19 views
0

有人能解釋我爲什麼這個代碼不工作:與行動()的委託任務並行庫

... 
foreach (VisualChunk chunk in SortedChunks) 
{ 
    System.Action a =() => MyFunction_Threaded(chunk); 
    Console.Write("Synchronous : "); 
    a.Invoke(); 
    System.Threading.Tasks.Task.Factory.StartNew(
             a, 
             CancellationToken.None, 
             TaskCreationOptions.None, 
             TaskScheduler.Default) 
} 
... 

private void MyFunction_Threaded(VisualChunk chunk) 
{ 
     Console.WriteLine(chunk.ChunkID); 
} 

它給了我下面的輸出在控制檯:

Synchronous : 0 
Synchronous : 1 
Synchronous : 2 
Synchronous : 3 
Synchronous : 4 
Synchronous : 4294967291 
Synchronous : 4294967292 
Synchronous : 4294967293 
Synchronous : 4294967294 
Synchronous : 4294967295 
Synchronous : 4294967296 
Synchronous : 4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
4294967297 
Synchronous : 4294967298 
4294967298 

其實這個代碼是當.net framework 4.5安裝時(win 8或VS2012)完美工作。 當只安裝4.0時,這個問題正在增加!

+3

捕獲的循環變量。再次...搜索堆棧溢出的那個術語。考慮到有多少人遇到這個問題,這顯然是語言上的一個缺陷。 – usr

+0

@usr我會說它*是*語言中的缺陷。它已被修復在C#5中。 – svick

+0

@svick誰知道?!這是否曾經宣佈過某處(除了規範)?我只知道他們正在考慮這一步,而不是他們真的接受了。 C#5中最隱藏的新功能之一。 – usr

回答

1

是的,正如上面@usr的註釋中提到的那樣,代碼中的問題是您已經「修改了閉包」,其中編譯器在構建彙編語言時會錯誤地解釋您想要執行的操作。這是一個非常糟糕的設計選擇在C#語言。要解決它,你需要把這些變量的副本在循環的時候了:

foreach (VisualChunk chunk in SortedChunks) 
{ 
    var chunkA = chunk; 
    System.Action a =() => MyFunction_Threaded(chunkA); 
    ... 

不過,我要問的這個點是什麼(即什麼是你想與實現這個代碼)?

+0

發送你的答案。我誤導的地方是我正在使用一個框架4.0要求的項目。在Win 8下的Windows 8或VS 2012下,代碼運行良好。但是,安裝Win 7而沒有安裝4.5框架的相同代碼會引發錯誤。這段代碼沒有理由,它是一個非常簡化的示例(用於論壇),試圖解釋這個問題。 – Fabian

+0

我真的認爲這個「突破」的變化應該更多地由微軟推動。我相當肯定,我不會是第一個在C#5下運行完美的代碼,這將在C#4下出現錯誤。 – Fabian