使用外部變量的lambda實際上捕獲變量,而不是存儲在其中的值。這意味着隨着循環的進行,您從捕獲的變量中讀取的值也會改變。
你可以通過在循環中使用一個臨時變量來解決這個問題。您的代碼將是更清潔了很多但如果你使用async/await
代替ContinueWith和lambda表達式,如:
for (int i=0;i<N;i++)
{
//...
var result=await thatOtherAsyncMethod(...);
ProcessResult(i, result));
}
在一般情況下,你可以通過複製循環變量進入循環的範圍內定義的變量避免捕獲的問題。
這解決了問題,因爲臨時變量只存在於循環體內。拉姆達是也循環體內創建,捕捉局部的,不變的變量:
for (int i=0;i<N;i++)
{
var temp=i;
var myLambda = new Action(()=>MyMethod(temp));
//This runs with the local copy, not i
myLambda();
}
的雖然更好的方法,是避免捕獲和傳遞迴路值作爲狀態參數ContinueWith
,例如:
for (int i = 0; i < N; ++i)
{
//...
var task = anotherTask.ContinueWith(
(t,state) => ProcessResult((int)state, t.Result),
i);
//...
}
爲什麼使用'ContinueWith'而不是等待?至於'i',你的lambda捕獲*變量*而不是變量的值。當實際讀取它時,讀取'i'將返回包含'i''的任何內容 - 實際執行對'ProcessResult(i,..)'的調用時。這是預期的行爲。使用'await'將解決這個問題,通過消除lambda *和*簡化代碼 –
來鏈接任務。這些可以長時間運行,而等待會暫停當前線程。 – Hector
不,它不會。 'await' *等待*,不會阻止。它相當於'ContinueWith',而不是'Wait'。它使鏈接更容易*,因爲它不需要lambdas和捕獲。 –