Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping through a list of Actions

I can't understand how to loop through an Action list. When I try it, I end up with the values being the same as 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();

Output:

ghi
ghi
ghi

Why is it always selecting the final element in strings when it performs the action?
And how can I achieve the desired output which would be:

abc
def
ghi
like image 769
demoncodemonkey Avatar asked Mar 05 '12 15:03

demoncodemonkey


People also ask

How do you make a loop that goes through a list?

You can loop through the list items by using a while loop. Use the len() function to determine the length of the list, then start at 0 and loop your way through the list items by referring to their indexes.

What does iterating through a list mean?

Iterating a list means going through each element of the list individually. We iterate over a list whenever we need to use its elements in some operation or perform an operation on the elements themselves.

Can you iterate through a list?

Iterating over a list can also be achieved using a while loop. The block of code inside the loop executes until the condition is true. A loop variable can be used as an index to access each element.

Can a for loop be used to iterate over a list?

A for loop iterates through items the same way as while and do-while loops, but it can also iterate through a list or set.


1 Answers

This behaviour is conditionize by Closures.

The variable that is present in your lambda is a reference and not value copy. That means that points to the latest value assumed by str, which is "ghi" in your case. That's why for every call it just goes to the same memory location and recovers, naturally, same value.

If you write the code, like in answers provided, you force a C# compiler to regenerate a new value each time, so a new address will be passed to the labmda, so every lambda will have it's own variable.

By the way, if I'm not mistake, C# team promise to fix this non natural behaviour in C# 5.0. So it's better to check their blog on this subject for future updates.

like image 198
Tigran Avatar answered Sep 26 '22 18:09

Tigran