2012-01-09 105 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);