Let's start with some source data to query:
int[] someData = { 1, 2 };
After running the following code, things work as I expect: a contains 2 elements which boil down to 1 and 2 pulled from someData.
List<IEnumerable<int>> a = new List<IEnumerable<int>>();
a.Add(someData.Where(n => n == 1));
a.Add(someData.Where(n => n == 2));
But this next code, which does exactly the same thing only in a loop, does not work as expected. When this code completes, b contains 2 elements but they are both identical - pointing to 2. On the 2nd loop, it modifies the first element of b.
List<IEnumerable<int>> b = new List<IEnumerable<int>>();
for (int i = 1; i <= 2; ++i)
{
    b.Add(someData.Where(n => n == i));
}
Why is this happening and how can I make the loop version behave like the first version?
Jon Skeet has a nice answer here
You need to assign i to a temp variable and use that in the Linq query
List<IEnumerable<int>> b = new List<IEnumerable<int>>();
for (int i = 1; i <= 2; ++i)
{
    int temp = i;
    b.Add(someData.Where(n => n == temp));
}
                        Your problem is lazy evaluation. You add an Enumerable to b that represents someData.Where(n => n == i). This is evaluated whenever you look into an element of b with the value i has at that time.
You want to manifest the enumerable by calling ToArray() or ToList() on it.
for (int i = 1; i <= 2; ++i)
{
    b.Add(someData.Where(n => n == i).ToArray());
}
Alternatively you can reduce the scope of the captured variable:
for (int i = 1; i <= 2; ++i)
{
    int localI=i;
    b.Add(someData.Where(n => n == localI));
}
Then you still have lazily evaluated enumerables(which shows when you modify someData), but each has a different i.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With