2012-01-09 53 views
5

我已经写了一个扩展方法来添加项目到(EF)EntityCollection。我收到了一个有趣的错误,说我收集的IEnumerable(“items”)在foreach的第一个循环之后被修改了。当我将项目变成items.ToList()(如下面的代码)时,它工作正常。C#修改IEnumerable之谜,什么是修改我的IEnumerable?

我完全理解做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); 
    } 
+3

'Remove'修改它,所以不会添加。 – vcsjones 2012-01-09 14:10:07

+2

@vcsjones虽然这是事实,但在这种情况下并不那么简单。 – 2012-01-09 14:12:58

+1

你的情况是'items == collection'吗? – 2012-01-09 14:26:53

回答

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

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

+2

但迭代是通过一个不同的集合(项目) – Erix 2012-01-09 14:23:59

+0

确实我upvoted这个,但在尝试它,这不会导致任何问题。 – 2012-01-09 14:33:04

+0

事实上,Erix,Adam,我已更新该帖子以阐明。 – sebastiaan 2012-01-09 14:35:07

0

也许EntityCollection不喜欢有人接管它的元素?所以,当你加入collection时,物品会从items中删除。

或者它可能是items == collection

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将突变集合并导致此异常。

+0

谢谢,但是这和.ToList()一起工作,因为集合和项目确实是不同的对象。我认为我的收藏对象可能会受到EF的跟踪机制的影响,会再次更新帖子。 :-) – sebastiaan 2012-01-09 16:59:25

+0

@sebastiaan是的,我注意到它没有'ToList'也可以工作,但我保持它类似于你提供的代码来证明问题出现在哪里。 – 2012-01-09 17:00:07

0

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

然后,它可能是EntityCollection认为它已经改变,因为它使用ID排序或在内部做其他事情。因此,foreach操作(可能使用相同的列表)引发异常。这也是为什么Adam Houldsworth证明的测试案例不能解决问题的原因!

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