我有以下代码,它修改了foreach
循环内集合的状态,
但是,它不会抛出任何异常。
// _topQueue.QueuedJobs is of type List<Job>
var slaJobs = _topQueue.QueuedJobs
.Where(job => job.JobInformation.SLA.HasValue)
.OrderBy(job=>job.ScheduledPriority);
foreach (var job in slaJobs) {
// Why this does not throw the exception:
// "collection was modified enumeration operation may not execute."
job.SetRunning();
job.JobInformation.StaticPriority = (int)Common.DjsConstant.PriorityPenalty;
job.ReprioritizedPriority = (int)Common.DjsConstant.PriorityBlocking;
}
另一方面,这段代码确实抛出异常:
//_topQueue.QueuedJobs is of type List<Job>
foreach (var job in _topQueue.QueuedJobs) {
job.SetRunning();
job.JobInformation.StaticPriority = (int)Common.DjsConstant.PriorityPenalty;
job.ReprioritizedPriority = (int)Common.DjsConstant.PriorityBlocking;
}
有人知道为什么吗?
foreach
循环中的哪些确切修改会导致异常?
答案 0 :(得分:3)
我很确定这是因为你有OrderBy
枚举整个集合才能给出任何结果。因此,原始集合已被完全读取,因此,更改原始集合不会影响OrderBy
已准备好的结果。
防止异常的简单解决方案是在linq查询中添加.ToList()
。然后结果是一个列表,并在内部更新对象不会影响列表的内容。
// _topQueue.QueuedJobs is of type List<Job>
var slaJobs = _topQueue.QueuedJobs
.Where(job => job.JobInformation.SLA.HasValue)
.OrderBy(job=>job.ScheduledPriority)
.ToList();
foreach (var job in slaJobs) {
// etc
}
答案 1 :(得分:0)
IEnumerable<T>
用于枚举,而不是修改。尽量避免修改枚举。
答案 2 :(得分:0)
有趣。 第一个枚举在子集上循环,而第二个枚举在所有元素上循环。
现在,如果第一个子集上的操作(即您提到的“删除”)不会影响子集本身,则它可能不会抱怨,因为查询背后的代码无法识别删除。当然,这只是一个理论。证明它(或至少获得更多信息): 删除的真正影响是什么?它会以任何方式改变或影响子集吗?
答案 3 :(得分:0)
我的建议是,job.SetRunning()中的方法中的某些内容正在从_topQueue.QueuedJobs中的集合中删除它。在第一个示例中,通过返回linq语句的结果,您将获得一个独立于原始_topQueue.QueuedJobs的克隆枚举。