从一个集合中删除的项目也会隐式地从第二个集合中删除,为什么?

时间:2016-09-02 11:24:55

标签: c# .net collections

对我来说这是一个很大的混乱。我有以下代码:

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:集合已被修改。为什么呢?

2 个答案:

答案 0 :(得分:1)

Enumerable.Except会返回设置差异的IEnumerable<T>,但它会延迟,这意味着它仍然只是查询。因此每次你都会触摸&#34; data您将执行此查询。所以,如果你想要一个物化的&#34;您必须使用ToListToArrayToLookupToDictionary(或将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可以想象为特定集合的视图,它不是自己的集合。因此,当项目从原始集合中删除时,我的枚举也被更改了。