我有一个对象列表,我想删除满足条件的所有对象。这是我的代码:
var listCurrentBuzzCompaigns = _buzzService.GetAllActiveCompaigns().ToList();
listCurrentBuzzCompaigns.ForEach(x => {
if (x.MayaMembership.MayaProfile.MayaProfileId == profile_id)
listCurrentBuzzCompaigns.Remove(x);
});
但是一个广告系列被删除,下一个广告系列不被删除,下一个广告系列被删除,下一个广告系列不被删除。代码有什么问题?
答案 0 :(得分:9)
你在迭代它时修改列表,这是不好的。请改用List<T>.RemoveAll
方法:
listCurrentBuzzCompaigns.RemoveAll(x => x.MayaMembership.MayaProfile.MayaProfileId == profile_id);
通常,当您使用foreach
关键字迭代List<T>
时,如果检测器检测到列表已被修改,则枚举器将抛出InvalidOperationException
。此行为旨在防止您遇到的错误。不幸的是,List<T>.ForEach
方法在内部不使用枚举器,因此不会抛出任何异常来警告您可能存在的错误。 foreach
和ForEach
之间的这种不一致对我来说似乎是一个设计缺陷。
更新:正如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);