2
int[] div = new int[] {2,3,5};
IEnumerable<int> seq = new int[] {10,15,20,25,30};
int x;
for (int i=0; i<div.Length; i++){
  x = div[i];
  seq = seq.Where( s=> s%x ==0);
}
seq = seq.ToList();

AND

int[] div = new int[] {2,3,5};
IEnumerable<int> seq = new int[] {10,15,20,25,30};
for (int i=0; i<div.Length; i++){
  int y = div[i];
  seq = seq.Where( s=> s%y ==0);
}
seq = seq.ToList();

The first seq's final value is 10,15,20,25,30 and the second one's is 30. I'm a little confused about the difference between int x; and int y = div[i]; . Can someone explain this to me?
Thanks!

Mohit S
  • 13,723
  • 6
  • 34
  • 69
S.C
  • 107
  • 7
  • 1
    This must be a duplicate from somewhere... basically in the first case, all the lambda expressions are capturing the same variable. In the second, each lambda expression captures a different variable. – Jon Skeet Sep 21 '15 at 08:47
  • Check this [SO post](http://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp) @JonSkeet explains there what's happening - you have the same case. Btw as far as I remember, this is not the case in `.NET 4.5+` anymore, both code blocks would have same results. – Michael Sep 21 '15 at 08:52
  • 1
    @Michael: No, a) it's not a difference in .NET 4.5, it's a difference in C# 5 regardless of the target framework; b) the difference is in how `foreach` loops are handled, and there isn't one here. – Jon Skeet Sep 21 '15 at 08:53
  • @JonSkeet thanks for clarification. Not sure I follow point `b)`. Are you suggesting in C# 5 this behavior will be still different for `for`, `while` loops (btw going to fire up Visual Studio and check for myself, but would like to see your input on this) ? – Michael Sep 21 '15 at 09:00
  • @Michael: Yes, variables declared inside a loop effectively behave differently to those declared outside a loop, in terms of capture. C# 5 just changed whether the `foreach` iteration variable counted as "inside" or "outside". – Jon Skeet Sep 21 '15 at 09:01
  • @JonSkeet I see now, thanks for clarification! – Michael Sep 21 '15 at 09:09

2 Answers2

5

Invoking seq = seq.Where( s=> s%x ==0); does not iterate over elements. It only creates an IEnumarable encapsulating the iteration, that can be iterated in fututre.

So if you declare your x variable before the loop, the lambda, that you passed in Where() uses the same variable. Since you are changing its value in a loop, eventually only the last one will be actually used.

Instead of expression like:

seq.Where( s=> s % 2 == 0).Where( s=> s % 3 == 0).Where( s=> s % 5 == 0);

you get:

seq.Where( s=> s % 5 == 0).Where( s=> s % 5 == 0).Where( s=> s % 5 == 0);
Kędrzu
  • 2,385
  • 13
  • 22
  • I am bit confused over here when the OP uses `int y` the last value is captured which is `5`..so the seq {10,15,20,25,30} is executed against '5' .But how does that explain output to be `30` ? – Rohit Sep 21 '15 at 09:42
  • No, in the second example variable is 2, 3 and then 5. Only 30 is dividible by all of these numbers. – Kędrzu Sep 21 '15 at 09:47
  • Variable `y` is defined **inside** the loop code block, so lamba uses different value for every iteration. – Kędrzu Sep 21 '15 at 09:48
2

The result is different because you are using lambda expression in the LINQ's Where() parameter. The actual execution of the all lambdas in Where()'s is performed on the very last row of both examples - the line where you perform .ToList(). Have a look at the Variable Scope in Lambda Expressions

The difference in the examples is how you initialize x/y.

In the first example there is only one memory slot for the variable x regardless of number of iterations of the foreach. The x always points to the same spot in the memory. Therefore there is only one value of the x on the last row and it is equal to the div[2].

In the second example there is separate memory slot created for y in each iteration of the loop. As the program evaluates, the address where y points to is changed in every iteration of the foreach. You might imagine it as there are multiple y variables like y_1, y_2,... Hence when evaluating the actual lambdas in Where()s the value of the y is different in every one of them.

mancze
  • 669
  • 6
  • 22