我在使用以下代码时遇到了一些问题:
AllAgents.CollectionChanged += (sender, e) =>
{
if (e.Action != NotifyCollectionChangedAction.Remove) return;
foreach (var s in AllSnapshots)
{
foreach (var stat in s.Stats.Where(stat => stat.Model.Agent == null))
s.Stats.Remove(stat);
}
};
这当然会抛出“Collection已被修改;枚举操作可能无法执行”。对我来说完全有意义的例外。问题是,从ObservableCollection中删除Model.Agent属性为null的所有项目的最佳方法是什么?我也对其他解决方案持开放态度,实质上,当从AllAgents集合中删除代理时,我需要从我的AllSnapshots.Stats集合中删除任何引用该代理的条目。
答案 0 :(得分:3)
从这样的集合中删除项目的最佳方法是使用标准的for
循环结构并向后迭代集合。由于您不再依赖枚举器来迭代集合,因此您可以安全地修改它而不会干扰循环。
反向迭代可防止在循环过程中删除干扰索引,否则会导致某些元素最终无法被删除。
ObservableCollection<Stat> o = new ObservableCollection<Stat>();
for (int i = o.Count - 1; i >= 0; i--) {
if (o[i] == null)
o.RemoveAt(i);
}
答案 1 :(得分:1)
问题是你正在迭代和删除并尝试再次迭代。 ObservableCollection
不支持此功能,因为它不会跟踪哪些元素已被删除。
将您的foreach
替换为不依赖于未修改的Collection的标准编号,并且全部。
这个解决方案延迟了Sam我的回复是不使用额外的内存来创建另一个列表(如果你的元素数量足够大,这可能相当昂贵)。
答案 2 :(得分:0)
我可能会做的是生成一个要删除的统计信息列表,然后在单独的foreach循环中将它们全部删除
foreach (var s in AllSnapshots)
{
list<object> stats = new list<object>
//if this doesn't work i'll leave it up to you to look up how to list a generic type
foreach (var stat in s.Stats.Where(stat => stat.Model.Agent == null))
stats.add(stat);
foreach(var stat in stats)
s.Stats.Remove(stat);
}
答案 3 :(得分:0)
如果每张快照的统计数据都相当低,我可能会这样做:
foreach(var s in AllSnapShots)
{
s.Stats = new ObservableCollection<Stats>(s.Where(stat =>stat.Model.Agent != null));
}
因此,将使用不 null的元素构建新集合。但是,如果统计数据列表相当大,您也可以这样做:
List<WhateverYourCollectionWasOf> statsToDelete;
foreach(var s in AllSnapShots)
{
statsToDelete.AddRange(s.Stats.Where(stat => stat.Model.Agent == null));
foreach (var stat in statsToDelete)
{
s.Stats.Remove(stat);
}
}
或者,如果你想成为未来的证据,你可以写一个扩展方法来做这类事情:
public static class ExtensionMethods
{
public static ObservableCollection<T> RemoveAll<T>(
this ObservableCollection<T> collection, Func<T, bool> predicate)
{
List<T> collectionAsList = collection.ToList();
List<T> itemsToRemove = collection.Where(predicate);
collectionAsList.RemoveAll(i => itemsToRemove.Contains(i));
collection = new ObservableCollection<T>(collectionAsList);
return collection;
}
}
然后会这样调用:
foreach(var s in AllSnapShots)
{
s.Stats.RemoveAll(stat => stat.Model.Agent == null);
}