C#修改IEnumerable的谜团,修改我的IEnumerable是什么?

时间:2012-01-09 14:07:54

标签: c# extension-methods ienumerable

我编写了一个扩展方法来向(EF)EntityCollection添加项目。我收到一个有趣的错误,说我的IEnumerable(“items”)集合在foreach的第一个循环之后被修改了。当我将项目转换为items.ToList()(如下面的代码中),它工作正常。

我完全理解,做ToList()会生成foreach将在其上运行的项目的副本。

我不明白的是当我对它进行预测时修改IEnumerable的内容。

更新:不知何故,似乎items变量与集合变量相同?

更新2:我认为收藏和实体可能会受到EF实体跟踪的影响,但我仍然无法理解为什么

用法:

ssp.ServiceAreas.ReplaceCollection(model.ServiceAreas);

这是我的扩展方法:

    public static void AddOrUpdate<TEntity>(this EntityCollection<TEntity> collection, IEnumerable<TEntity> items)
        where TEntity : EntityObject, IProjectIdentity<int>, new()
    {
        foreach (var item in items.ToList())
            collection.AddOrUpdate(item);
    }

    public static void AddOrUpdate<TEntity>(this EntityCollection<TEntity> collection, TEntity item)
        where TEntity : EntityObject, IProjectIdentity<int>, new()
    {
        if (item.ID > 0 && collection.Any(c => c.ID == item.ID))
            collection.Remove(collection.First(c => c.ID == item.ID));
        // For now, the Remove NEVER gets hit

        collection.Add(item);
    }

5 个答案:

答案 0 :(得分:4)

collection.Remove(collection.First(c => c.ID == item.ID)); 

您要删除正在迭代的集合。

答案 1 :(得分:1)

我创建了以下示例代码:

internal class Program
    {
        private static void Main(string[] args)
        {
            var one = new List<string> {"Adam", "John"};

            var two = new List<string> {"Adam", "Houldsworth"};

            one.AddOrUpdate(two);

            Console.Read();
        }
    }

    static class Extensions
    {
        public static void AddOrUpdate(this IList<string> collection, IEnumerable<string> items)
        {
            foreach (var item in items.ToList())
                collection.AddOrUpdate2(item);
        }

        public static void AddOrUpdate2(this IList<string> collection, string item)
        {
            if (collection.Any(c => c == item))
                collection.Remove(collection.First(c => c == item));

            collection.Add(item);
        }
    }

这可以按照您的预期运行,没有错误。所以从本质上讲,这些线都没有引起问题。

如果您单独调用列表,会导致什么问题:

one.AddOrUpdate(one);

因此,从我所看到的,您必须使用与两个参数相同的集合来调用此扩展方法。

如果您是,那么RemoveAdd都会改变集合并导致此异常。

答案 2 :(得分:0)

当有人接管它的元素时,或许EntityCollection不喜欢?因此,当您添加到collection时,项目将从items中删除。

或者可能是items == collection

答案 3 :(得分:0)

可能是第一项始终是新项,因此默认情况下,ID设置为某个初始值。然后它将被添加到集合中,让EntityFramework生成一个新ID并将其分配给第一个添加的项目。

然后可能是EntityCollection认为它已经改变了,因为它使用ID来排序或在内部执行其他操作。因此,foreach操作(可能使用相同的列表)会抛出异常。这也是为什么Adam Houldsworth证明的测试用例没有给出问题的原因!

答案 4 :(得分:0)

EntityCollection<Customer> customers = new EntityCollection<Customer>();
Customer newCustomer = new Customer() {ID = 0};
customers.Add(newCustomer);
customers.AddOrUpdate(customers);