0

I was trying to test this case of resusing the loop variable in foreach in c# as mentioned in following question

Is there a reason for C#'s reuse of the variable in a foreach?

After going through this and this, i tried to reproduce this error with for loop as foreach part has been fixed in c# releases.

But to my surprise, when i tried this code, I got an "Index was outside the bounds of the array." exception from code. Although my array has 4 items and i am trying to access the 3rd index.

public static void Main()
{
var strings = new string[] { "sd2", "dafs3", "dasd5", "fdf6" };
var actions = CreateActions(strings);
actions.ForEach(f => f());
}
private static List<Action> CreateActions(string[] strings)
{
   var actions = new List<Action>();
   for (int i = 0; i < 4; i++)
   {
      Console.WriteLine(i);
      var fiber = strings[i];
      actions.Add(() => Console.WriteLine(strings[i]));
   }
  return actions;
}

Then I changed my code like this

public static void Main()
{
var strings = new string[] { "sd2", "dafs3", "dasd5", "fdf6" };
var actions = CreateActions(strings);
actions.ForEach(f => f());
}
private static List<Action> CreateActions(string[] strings)
{
   var actions = new List<Action>();
   for (int i = 0; i < 4; i++)
   {
      Console.WriteLine(i);
      var fiber = strings[i];
      actions.Add(() => Console.WriteLine(fiber));
   }
  return actions;
}

This code is running fine and i got no out of range exception which is strange. Also regarding reusing variable my case was proved.

My first code has this output if run upto index 2 in for loop as for index 3 it throw out of range exception.

0
1
2
fdf6
fdf6
fdf6

My second code piece gave this output and list all 4 items in output

0
1
2
3
sd2
dafs3
dasd5
fdf6

Is there any explanation with c# or any issue with my test code.

Rohit
  • 330
  • 1
  • 5
  • 16
  • 5
    In the first version, when the `actions` are executed, the loop has already completed. When does the loop complete? When `i` is greater than `4`. They're all sharing the same copy of `i`, which is equal to `5` at the time they're called. In the second version, you're creating a local variable `fiber` whose scope is limited to the `for` block -- so each action has its own personal copy of `fiber`, with the correct value. `foreach` loops don't have this issue (I don't recall which C# version fixed it). `for` loops do. This is a classic gotcha, and a duplicate. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 13:28
  • 3
    @GrantWinney It's fixed in `foreach`, where the loop variable must be declared in the parens. Fixing it in `for` would seem to be a bigger deal, at the very least. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 13:30
  • But so anyway, `foreach (var fiber in strings) {...}` would resolve the issue, though you've also stumbled on another valid solution. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 13:31
  • 1
    but why downvote, i found no relevant question in popped suggestions, all those were simple out of range examples. Also I researched a lot before posting,provided the links.. :( – Rohit Jul 06 '17 at 13:32
  • @Rohit Your question certainly taught me something new! Thanks! – Blake Thingstad Jul 06 '17 at 13:40
  • thanks @BlakeThingstad, i had the same intention while posting this question. – Rohit Jul 06 '17 at 13:41
  • 1
    @Rohit Likely somebody thought you should have figured out that this is the closure/loop-variable issue, which does very often manifest as an index out of range exception. Either that or somebody didn't like your indenting, who knows. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 13:53
  • 1
    @EdPlunkett still i learned few things :) . and at least when next guy is going to put such question, he might have this question in suggestions.. – Rohit Jul 06 '17 at 13:57

0 Answers0