【发布时间】:2019-05-02 20:53:26
【问题描述】:
我最近遇到了一个问题,我能够更改在 foreach 循环中迭代的 IEnumerable 对象。我的理解是,在 C# 中,您不应该能够编辑您正在迭代的列表,但经过一番挫折后,我发现这正是正在发生的事情。我基本上循环了一个 LINQ 查询并使用对象 ID 在数据库中对这些对象进行更改,这些更改影响了 .Where() 语句中的值。
有人对此有解释吗?似乎每次迭代时 LINQ 查询都会重新运行
注意:解决此问题的方法是在 .Where() 之后添加 .ToList(),但我的问题是为什么会发生这个问题,即如果这是一个错误或我不知道的事情
using System;
using System.Linq;
namespace MyTest {
class Program {
static void Main () {
var aArray = new string[] {
"a", "a", "a", "a"
};
var i = 3;
var linqObj = aArray.Where(x => x == "a");
foreach (var item in linqObj ) {
aArray[i] = "b";
i--;
}
foreach (var arrItem in aArray) {
Console.WriteLine(arrItem); //Why does this only print out 2 a's and 2 b's, rather than 4 b's?
}
Console.ReadKey();
}
}
}
此代码只是一个可重现的模型,但我希望它循环 4 次并将aArray 中的所有字符串更改为 b。但是,它只循环了两次,并将aArray中的最后两个字符串变成了b的
编辑:经过一些反馈并更简洁地说,我的主要问题是:“为什么我能够改变我正在循环的内容因为我正在循环它”。看起来压倒性的答案是 LINQ 确实延迟执行,因此在我循环遍历 LINQ IEnumerable 时它正在重新评估。
编辑2:实际上,似乎每个人都关心.Count() 函数,认为这就是这里的问题所在。但是,您可以注释掉该行,我仍然遇到 LINQ 对象更改的问题。我更新了代码以反映主要问题
【问题讨论】:
-
linqLIST是aArray数组的延迟执行过滤。与名称相反,它不是 一个列表,因此如果您已经阅读过不允许在迭代列表时更改列表,则会引发异常,这不一定适用于此。由于数组无法通知惰性求值的枚举器内部的变化,因此枚举器不会停止工作,相反,当它到达每个项目时,它将根据谓词过滤它。如果它下面的元素发生变化,这将影响尚未过滤的过滤项目。 -
因为它被推迟了,
.Count()实际上会强制进行一次评估,每次,这就是它不断变化的原因。 -
如果我做对了,您的问题是:1) 为什么我在枚举“列表”时可以更改它? 2) 为什么
.Count()在这种情况下会不断变化? 3) 每次迭代时,LINQ 查询是否都会重新运行? (简短的回答:是的,这可能应该回答所有其他问题的组合) 4)foreach 是如何真正工作的? -
如果你想了解这个游乐场sharpLab
-
人们给出答案后,您不应该更改问题来源。