1

我在使用以下代码时遇到了一些问题:

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);
                }
            };

这当然会抛出“集合已修改;枚举操作可能无法执行”。例外,这对我来说完全有意义。问题是,从我的 ObservableCollection 中删除 Model.Agent 属性为空的所有项目的最佳方法是什么?我也对其他解决方案持开放态度,本质上,当从 AllAgents 集合中删除代理时,我需要从我的 AllSnapshots.Stats 集合中删除引用该代理的所有条目。

4

4 回答 4

4

从这样的集合中删除项目的最佳方法是使用标准for循环构造并向后迭代集合。由于您不再依赖枚举器来迭代集合,因此您可以安全地修改它而不会干扰循环。

反向迭代可防止在循环过程中删除干扰索引,否则会使您面临某些元素最终不会被删除的可能性。

ObservableCollection<Stat> o = new ObservableCollection<Stat>();
for (int i = o.Count - 1; i >= 0; i--) {
    if (o[i] == null) 
        o.RemoveAt(i);                
}
于 2012-09-12T16:36:35.773 回答
1

问题是您正在迭代和删除并尝试再次迭代。这不受支持,ObservableCollection因为它不跟踪删除了哪些元素。

将您的替换foreach为不依赖于要修改的集合的标准编号,仅此而已。

这个解决方案推迟了 Sam 我的回答,因为它不使用额外的内存来创建另一个列表(如果你的元素数量足够大,这可能会非常昂贵)。

于 2012-09-12T16:33:52.933 回答
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);
}
于 2012-09-12T16:30:32.343 回答
0

如果每个 Snapshot 的 Stats 数量相当少,我可能会这样做:

foreach(var s in AllSnapShots)
{
    s.Stats = new ObservableCollection<Stats>(s.Where(stat =>stat.Model.Agent != 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);
}
于 2012-09-12T16:40:52.090 回答