来自 IEnumerable 的项目在 foreach 内部发生了更改,但更改未保存到集合中
本文关键字:保存 集合 IEnumerable 项目 foreach 内部 来自 发生了 | 更新日期: 2023-09-27 17:50:33
我今天有一个有趣的问题,这是一个复制品:
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; }
}
}
在GetBool1()
中,更改item
的值对list
变量没有影响。
GetBool2()
按预期工作。
有人知道为什么会这样吗?
[关于重复标签]
我认为这基本上与这个问题中的问题相同,但这里的问题更简洁明了,所以我就不说了。
这是 LINQ 的惰性计算问题。每次在 GetBool1()
中迭代list
时,您都会创建一个新的值序列。更改其中一个对象中的 Value
属性不会更改任何其他内容。
将其与GetBool2()
进行比较,其中您可以调用ToList()
,这意味着您正在创建一个包含一系列对象的List<T>
。现在,每次遍历该列表时,您都会获得对相同对象的引用......因此,如果您修改其中一个对象中的值,您将在下次看到该值。
如果您将Select argument
更改为
> { Console.WriteLine("Selecting!"(; 返回新的布尔容器 { 值 = x } };
。然后添加适当的额外Console.WriteLine
调用,以便您可以看到它何时发生,您将看到在调用 ToList()
之后从未GetBool2()
调用委托,但GetBool1()
每次迭代序列时都会调用它。