在列表中调用删除<t> .ForEach只删除交替的项目?</t>

时间:2012-07-06 14:49:59

标签: c# .net list foreach lambda

我有一个对象列表,我想删除满足条件的所有对象。这是我的代码:

var listCurrentBuzzCompaigns = _buzzService.GetAllActiveCompaigns().ToList();

listCurrentBuzzCompaigns.ForEach(x => {
    if (x.MayaMembership.MayaProfile.MayaProfileId == profile_id)
        listCurrentBuzzCompaigns.Remove(x);
});

但是一个广告系列被删除,下一个广告系列不被删除,下一个广告系列被删除,下一个广告系列不被删除。代码有什么问题?

4 个答案:

答案 0 :(得分:9)

你在迭代它时修改列表,这是不好的。请改用List<T>.RemoveAll方法:

listCurrentBuzzCompaigns.RemoveAll(x => x.MayaMembership.MayaProfile.MayaProfileId == profile_id);

通常,当您使用foreach关键字迭代List<T>时,如果检测器检测到列表已被修改,则枚举器将抛出InvalidOperationException。此行为旨在防止您遇到的错误。不幸的是,List<T>.ForEach方法在内部不使用枚举器,因此不会抛出任何异常来警告您可能存在的错误。 foreachForEach之间的这种不一致对我来说似乎是一个设计缺陷。

更新:正如AlanT所说,另一种技术是在调用ToList之前过滤掉你不想要的项目。这是如何做到的:

var listCurrentBuzzCompaigns = _buzzService.GetAllActiveCompaigns()
    .Where(x.MayaMembership.MayaProfile.MayaProfileId != profile_id)
    .ToList();

请注意,我已通过将==更改为!=来反转条件。

答案 1 :(得分:2)

在显示的代码段中,您可能最好使用where()子句在获取广告时过滤广告系列,而不是在检索后删除它们。

e.g。

[TestMethod]
public void TestMethod1() {

   var campaigns = new List<Campaign>(){
       new Campaign {ProfileId = "Jan"},
       new Campaign {ProfileId = "Jan"},
       new Campaign {ProfileId = "Feb"},
       new Campaign {ProfileId = "Mar"},
       new Campaign {ProfileId = "Jan"},
       new Campaign {ProfileId = "Jan"},
   };


   var notJanCampaigns = campaigns.Where(c => c.ProfileId != "Jan");

   Assert.AreEqual(2, notJanCampaigns.Count());

}

class Campaign {
    public string ProfileId { get; set; }
} 

在您的代码中,您将过滤

x.MayaMembership.MayaProfile.MayaProfileId != profile_id

答案 2 :(得分:2)

如果你想在迭代它时从集合中删除元素,那么向后迭代它,如下所示:

List<Smurf> smurfs = GetSomeSmurfs();
for (in i = smurfs.Count - 1; i >= 0; i--)
{
   Smurf smurfToRemove = smurfs[i];
   if(conditionToRemoveSmurf)
   {
      //Do whatever you need with that smurf before removing it. 
      //(Dispose(), give to azrael, whatever)
      smurfs.Remove(smurfToRemove);
   }
}

实现此目的的相应扩展方法留给读者练习;)

答案 3 :(得分:1)

不要从你正在迭代的序列中删除东西!

所以,改为:

var x = listCurrentBuzzCompaigns.Where(x => x.MayaMemberShip.MayaProfile.PayaProfileId == profile_id).Single();
listCurrentBuzzCompaigns.Remove(x);