考虑以下示例:
IEnumerable<Int32> groupsToAdd = new List<Int32>();
List<Int32> groups1 = new List<Int32>() { 1,2,3 };
List<Int32> groups2 = new List<Int32>() { 3,4,5 };
groupsToAdd = groups1.Where(g => false == groups2.Contains(g));
groups2.AddRange(groupsToAdd);
groupsToAdd.Dump();
当调用groupsToAdd.Dump()
时,列表现在为空。我查找了AddRange引用,它没有提到元素已从列表中删除,但当我测试此代码(在linqpad中)时,它以空结束。为什么会这样?
编辑:为了澄清,我的意思是从groupsToAdd
中删除这些元素,因为在groups2.AddRange(groupsToAdd)
组ToAdd之前填充了两个元素
使用LINQ时,重要的是要记住,它会导致查询,而不是该查询的结果。groupsToAdd
不是一个项目列表,它只是一个查询的定义,它能够在需要时获得一些项目
groupsToAdd
在迭代之前不会实际迭代源序列(即groups1
)或执行谓词检查(这取决于groups2
的状态)。
您迭代groupsToAdd
两次。一次是呼叫AddRange
,另一次是调用Dump
。第二次迭代时,group2
发生了变化,因此查询的结果也发生了变化。
如果你想避免这种延迟执行,那么你可以通过将代码修改为来立即实现查询
groupsToAdd = groups1.Where(g => false == groups2.Contains(g));
.ToList();
这将在该时刻评估查询,以便groupsToAdd
将表示查询的结果,而不是查询本身。
这是因为IEnumerable。当您将groupsToAdd设置为groups1.Where(g => false == groups2.Contains(g))
的结果时,会延迟执行,这意味着查询直到AddRange()才运行,然后在Dump()处再次运行。因为列表groups2现在包含元素,所以它们不再是原始查询的结果。