Crossing the action list

I cannot figure out how to get through the Action list. When I try, I get values ​​similar to the previous iteration.

Here's the code (simplified example):

 string[] strings = { "abc", "def", "ghi" }; var actions = new List<Action>(); foreach (string str in strings) actions.Add(new Action(() => { Trace.WriteLine(str); })); foreach (var action in actions) action(); 

Conclusion:

 ghi ghi ghi 

Why does he always select the last element in strings when he performs an action?
And how can I achieve the desired result, which will be:

 abc def ghi 
+6
source share
3 answers

Your action is a closure, so it accesses str itself, not a copy of str :

 foreach (string str in strings) { var copy = str; // this will do the job actions.Add(new Action(() => { Trace.WriteLine(copy); })); } 
+13
source

This is a rather difficult situation. The short answer is to create a copy of the local variable before assigning it to closure:

 string copy = str; actions.Add(new Action(() => { Trace.WriteLine(copy); })); 

Check out this closure article for more information.

+3
source

This behavior is due to Closures .

The variable that is present in your lambda is a link and not . This means that it points to the last value accepted by str , which is "ghi" in your case. That is why for each call it simply goes to the same memory location and, naturally, gets the same value.

If you write code, as in the answers provided, you force the C# compiler to update the new value each time, so a new address will be sent to labmda, so each lambda will have its own variable.

By the way, if I'm not mistaken, the C# team promises to fix this unnatural behavior in C# 5.0 . Therefore, it is better to check your blog on this topic for future updates.

+3
source

Source: https://habr.com/ru/post/910006/


All Articles