I had an interesting problem today, this is a reproduction:
class TestListAndEnumerable
{
public static void Test()
{
bool b1 = GetBool1(); // returns false
bool b2 = GetBool2(); // returns true
}
private static bool GetBool1()
{
IEnumerable<BoolContainer> list = new List<bool> { false }.Select(x => new BoolContainer { Value = x });
foreach (BoolContainer item in list)
{
item.Value = true;
}
return list.Select(x => x.Value).First();
}
private static bool GetBool2()
{
List<BoolContainer> list = new List<bool> { false }.Select(x => new BoolContainer { Value = x }).ToList();
foreach (BoolContainer item in list)
{
item.Value = true;
}
return list.Select(x => x.Value).First();
}
private class BoolContainer
{
public bool Value { get; set; }
}
}
Inside GetBool1()
, changing the value of item
has no effect on the list
variable.
GetBool2()
works as expected.
Anyone know why this is happening?
[Regarding the duplicate tag]
I think it IS fundamentally the same problem as in this question, but the question here is more concise and to the point so I'll leave it.
This is a matter of LINQ's lazy evaluation. Each time you iterate over list
in GetBool1()
, you're creating a new sequence of values. Changing the Value
property in one of those objects doesn't change anything else.
Compare that with GetBool2()
, where you're got a call to ToList()
, which means you're creating a List<T>
with a sequence of objects in. Now each time you iterate over that list, you'll get references to the same objects... so if you modify the value within one of those objects, you'll see that next time.
If you change your Select argument
to
x => { Console.WriteLine("Selecting!"); return new BoolContainer { Value = x } };
... then add appropriate extra Console.WriteLine
calls so you can see when it's taking place, you'll see that the delegate is never called in GetBool2()
after the call to ToList()
, but in GetBool1()
it will be called each time you iterate over the sequence.
See more on this question at Stackoverflow