对我来说这是一个很大的混乱。我有以下代码:
IEnumerable<WorkflowStateData> data = model.Data.Except(
request.WorkflowState.CustomData.Select(x => new Model.WorkflowStateData {Key = x.Key}),
new WorkflowStateDataEqualityComparer());
foreach (var item in data) // makes the comparison (and exception) based on the value of property 'Key'
{
model.Data.Remove(item);
stateDataSet.Remove(item);
}
这应创建新的项集合,并使用foreach将其用于枚举。它应该从原始集合中删除项目,但它会从原始集合和“数据”集合中删除它并抛出InvalidOperationException:集合已被修改。为什么呢?
答案 0 :(得分:1)
Enumerable.Except
会返回设置差异的IEnumerable<T>
,但它会延迟,这意味着它仍然只是查询。因此每次你都会触摸&#34; data
您将执行此查询。所以,如果你想要一个物化的&#34;您必须使用ToList
,ToArray
,ToLookup
或ToDictionary
(或将foreach
循环中的结果添加到另一个集合中)。
如果您尝试修改当前在foreach
中枚举的集合,通常甚至会出现异常。因此,您可以使用ToList
创建一个真实的集合,如果您修改它的源代码,则不会受到影响:
List<WorkflowStateData> data = model.Data.Except(
request.WorkflowState.CustomData.Select(x => new Model.WorkflowStateData {Key = x.Key}),
new WorkflowStateDataEqualityComparer())
.ToList();
现在,您可以从原始集合中删除对象,而无需将其从列表中删除。
您应该阅读LINQ的延期执行/急切评估。
答案 1 :(得分:0)
答案非常简单,但由于使用了那个具有叛逆性的“var”关键字而不明显。 Except返回IEnumerable,而不是ICollection。 IEnumerable可以想象为特定集合的视图,它不是自己的集合。因此,当项目从原始集合中删除时,我的枚举也被更改了。