我今天遇到了一个有趣的问题,这是一个复制:
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
在里面GetBool1(),改变值item对list变量没有影响.
GetBool2()按预期工作.
任何人都知道为什么会这样吗?
[关于重复标签]
我认为,它从根本上是同一个问题在这个问题,但这里的问题是更简洁,重点突出,所以我会离开它.
Jon*_*eet 14
这是LINQ懒惰评估的问题.每次迭代list时GetBool1(),都会创建一个新的值序列.更改Value其中一个对象中的属性不会更改其他任何内容.
将其与GetBool2()您调用的地方进行比较ToList(),这意味着您正在List<T>使用一系列对象创建一个.现在每次遍历该列表时,您将获得对相同对象的引用...所以如果你修改其中一个对象中的值,下次你会看到.
如果你改变你Select argument的
x => {Console.WriteLine("选择!"); 返回新的BoolContainer {Value = x}};
...然后添加适当的额外Console.WriteLine调用,以便您可以看到它何时发生,您将看到在调用GetBool2()之后从未调用委托ToList(),但是GetBool1()每次遍历序列时都会调用它.