static void Main(string[] args)
{
Program p = new Program();
p.TestAsyncInLoop();
}
private void TestAsyncInLoop()
{
var tasks = new List<Task>();
for (int i = 0; i < 20; i++)
{
//tasks.Add(Task.Run(() => PrintNo(i)));
var ii = i;
tasks.Add(Task.Run(() => PrintNo(ii)));
}
Task.WaitAll(tasks.ToArray());
}
private async Task PrintNo(int no)
{
Console.WriteLine(no);
}
Inside the for loop, I'm calling an async method "PrintNo(int no)" passing a parameter "i" which is value type (int). When the method starts to execute, the value of "no" equals to the current value of i (which is probably 20) not the value that was sent initially in the loop! A solution I did is copying the value of "i" before sending to a new variable "ii". This solution worked fine, but can you explain why the value of "i" was not copied to the method as in sync methods? (not working code is //commented)
Your interpretation of the behavior is slightly off. You are not calling the function in the loop. The call is inside of the lambda. The argument passing is totally OK and by value. The capture of i
is the problem. This has nothing to do with async.
Since C# 5 this problem is fixed with foreach
. Use foreach
.
As a subjective note I feel that for
loops have become mostly a code smell since we have LINQ. It's quite rare to see a genuine use case for them. I guess here it's alright as a counting loop.