LINQ 在使用 .Where() 遍历并修改 ienumerable 过滤器中的项目后,项目消失了 - 为什么?
LINQ after looping over and modifying items in enumerable filtered with .Where(), items disappear - why?
在修复一些代码的错误时,我 运行 出现了一些意外行为,似乎在遍历 IEnumerable 之后项目从它消失了。
我试图理解为什么会发生这种情况,我编写了一个小测试项目来测试这种行为。
下面简单解释一下代码,
- 我有一个 class (TestObject),它有一个 属性 - 一个 int
- 我创建了一个 TestObject 列表,并向其中添加了 5 个新的 TestObject,它们都带有 int 属性 == 5
- 我用 LINQ 的 .Where() 函数“过滤”列表,只获取 int == 5 的 TestObjects
(列表中的每个元素)
- 我遍历 IEnumerable 的元素,将每个元素的 int 属性 设置为 0
- IEnumerable 现在为空
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestingGroundProject
{
class TestObject
{
public TestObject(int intVal)
{
IntVal = intVal;
}
public int IntVal { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<TestObject> testList = new();
for (int i = 0; i < 5; i++)
testList.Add(new TestObject(5));
//this line results in expected behavior
//(5 elements in testEnum, all IntVal's are 0 after the loop)
//var testEnum = testList.AsEnumerable();
//this line results in unexpected behavior
//(0 elements in testEnum after the loop)
var testEnum = testList.Where(t => t.IntVal == 5);
//prints "5"
Console.WriteLine(testEnum.Count());
foreach (var t in testEnum)
t.IntVal = 0;
//prints "0"
Console.WriteLine(testEnum.Count());
}
}
}
我猜这与 yield return 有关,它在 .Where() 的后台完成,它获取可枚举中与谓词匹配的下一个元素,我'我通过在遍历它时更改可枚举的元素来干扰它,但是有人可以 confirm/explain 这个吗?
(我确实尝试在 this link 查找有关 .Where() 函数行为的任何文档,但它并没有真正回答我的问题。)
这也是为什么 .AsEnumerable() 似乎没有这个问题的原因吗?
感谢您的宝贵时间。
IEnumerable 在您调用需要迭代的东西之前不会执行,例如您的 Count()。所以你调用 Count() 的两次序列将被单独计算。这就是物品第二次消失的原因。如果您希望将序列保持在给定点,您可以调用 ToList() 并将其保存在变量中。
在修复一些代码的错误时,我 运行 出现了一些意外行为,似乎在遍历 IEnumerable 之后项目从它消失了。
我试图理解为什么会发生这种情况,我编写了一个小测试项目来测试这种行为。
下面简单解释一下代码,
- 我有一个 class (TestObject),它有一个 属性 - 一个 int
- 我创建了一个 TestObject 列表,并向其中添加了 5 个新的 TestObject,它们都带有 int 属性 == 5
- 我用 LINQ 的 .Where() 函数“过滤”列表,只获取 int == 5 的 TestObjects
(列表中的每个元素) - 我遍历 IEnumerable 的元素,将每个元素的 int 属性 设置为 0
- IEnumerable 现在为空
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestingGroundProject
{
class TestObject
{
public TestObject(int intVal)
{
IntVal = intVal;
}
public int IntVal { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<TestObject> testList = new();
for (int i = 0; i < 5; i++)
testList.Add(new TestObject(5));
//this line results in expected behavior
//(5 elements in testEnum, all IntVal's are 0 after the loop)
//var testEnum = testList.AsEnumerable();
//this line results in unexpected behavior
//(0 elements in testEnum after the loop)
var testEnum = testList.Where(t => t.IntVal == 5);
//prints "5"
Console.WriteLine(testEnum.Count());
foreach (var t in testEnum)
t.IntVal = 0;
//prints "0"
Console.WriteLine(testEnum.Count());
}
}
}
我猜这与 yield return 有关,它在 .Where() 的后台完成,它获取可枚举中与谓词匹配的下一个元素,我'我通过在遍历它时更改可枚举的元素来干扰它,但是有人可以 confirm/explain 这个吗?
(我确实尝试在 this link 查找有关 .Where() 函数行为的任何文档,但它并没有真正回答我的问题。)
这也是为什么 .AsEnumerable() 似乎没有这个问题的原因吗?
感谢您的宝贵时间。
IEnumerable 在您调用需要迭代的东西之前不会执行,例如您的 Count()。所以你调用 Count() 的两次序列将被单独计算。这就是物品第二次消失的原因。如果您希望将序列保持在给定点,您可以调用 ToList() 并将其保存在变量中。