question:
I've had an interesting problem, and its code is probably like this.
List<Func<int>> actions = new List<Func<int>>(); int variable = 0; while (variable < 5) { (() => variable * 2); ++ variable; } foreach (var act in actions) { (()); }
My expected output is 0,2,4,6,8, but it ends up with five 10s, which look like these action contexts capture the same variable.
Is there a workaround to achieve the expected results I want?
Solution:
The workaround is to use an intermediate variable in your loop body and feed it into the lambda body, refer to the following code:
List<Func<int>> actions = new List<Func<int>>(); int variable = 0; while (variable < 5) { int variable1 = variable; (() => variable1 * 2); ++variable; } foreach (var act in actions) { (()); } ();
In fact, this situation will also happen under multi-threading, such as the following code:
for (int counter = 1; counter <= 5; counter++) { new Thread (() => (counter)).Start(); }
You thought you would print out 1,2,3,4,5. The final result is very interesting. The output result here is: 2,1,3,3,4. The result on your side must be different again.
The only solution is to use local variables, and the modified code is as follows:
for (int counter = 1; counter <= 5; counter++) { int localVar= counter; new Thread (() => (localVar)).Start(); }
Summarize
Many friends may not know why the code is correct after adding a variable1 variable. If you want to analyze it, you can look at the IL code generated in C#.
private static void Main(string[] args) { List<Func<int>> actions = new List<Func<int>>(); for (int variable = 0; variable < 5; variable++) { <>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0(); <>c__DisplayClass0_.variable1 = variable; (new Func<int>(<>c__DisplayClass0_.<Main>b__0)); } foreach (Func<int> act in actions) { (act()); } (); }
It can be clearly seen that the so-called variable1 has become a field under the anonymous class c__DisplayClass0_0, and the foreach loop is new every time, so this field must be different, which ensures the correct result.
This is the end of this article about how to capture local variables in C# loops. For more related content about C# loops to capture local variables, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!