【问题标题】:C# Modification of IEnumerable mystery, what is modifying my IEnumerable?C#修改IEnumerable之谜,什么是修改我的IEnumerable?
【发布时间】:2012-01-09 14:07:54
【问题描述】:

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

我完全明白,执行 ToList() 将生成 foreach 将在其上运行的项目的副本。

我不明白的是,当我对 IEnumerable 进行 foreach 时,是什么在修改它。

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

更新 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);
    }

【问题讨论】:

  • Remove 修改它,所以添加。
  • @vcsjones 虽然这是真的,但在这种情况下,事情并不是那么简单。
  • 你的情况是items == collection吗?
  • 您正在从您正在 foreach-ing 的集合中添加/删除项目(第一个方法为 foreach 块中的每个项目调用第二个,第二个是添加/删除东西)。
  • 第一:“items”和“collection”有什么区别?第二:删除实际上永远不会被击中,我会更新帖子。

标签: c# extension-methods ienumerable


【解决方案1】:
collection.Remove(collection.First(c => c.ID == item.ID)); 

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

【讨论】:

  • 但迭代是通过不同的集合(项目)
  • 确实,我对此表示赞同,但在尝试时,这不会导致任何问题。
【解决方案2】:

我创建了以下示例代码:

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 都会改变集合并导致此异常。

【讨论】:

  • 谢谢,但是无论有没有 .ToList() .. 都可以使用,因为集合和项目确实是不同的对象。我认为我的收藏对象可能会受到 EF 的跟踪机制的影响,将再次更新帖子。 :-)
  • @sebastiaan 是的,我注意到它在没有 ToList 的情况下也可以工作,但我保持它与您提供的代码相似,以证明问题出在哪里。
【解决方案3】:

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

也可能是items == collection

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:
      EntityCollection<Customer> customers = new EntityCollection<Customer>();
      Customer newCustomer = new Customer() {ID = 0};
      customers.Add(newCustomer);
      customers.AddOrUpdate(customers);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-09-12
        • 2011-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-07
        相关资源
        最近更新 更多