.net 从ObservableCollection中删除空项

bvpmtnay  于 2023-06-25  发布在  .NET
关注(0)|答案(5)|浏览(101)

我在处理以下代码时遇到一些问题:

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集合中删除引用该代理的所有条目。

zbdgwd5y

zbdgwd5y1#

从这样的集合中删除项的最好方法是使用标准的for循环构造并向后迭代集合。由于不再依赖枚举数来循环访问集合,因此可以安全地修改它,而不会干扰循环。
反向迭代可以防止删除在循环过程中干扰索引,否则可能会导致某些元素最终无法被删除。

ObservableCollection<Stat> o = new ObservableCollection<Stat>();
for (int i = o.Count - 1; i >= 0; i--) {
    if (o[i] == null) 
        o.RemoveAt(i);                
}
p4tfgftt

p4tfgftt2#

问题是你在迭代和删除,然后尝试再次迭代。ObservableCollection不支持这一点,因为它不会跟踪哪些元素被删除。
foreach替换为一个不依赖于集合不被修改的标准计数,仅此而已。
这个解决方案不同于Sam I am的回复,因为它不使用额外的内存来创建另一个列表(如果你的元素数量足够大,这可能会非常昂贵)。

x6492ojm

x6492ojm3#

我可能要做的是生成一个要删除的统计信息列表,然后在一个单独的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);
}
pb3s4cty

pb3s4cty4#

如果每个快照的统计数据数量相当少,我可能会这样做:

foreach(var s in AllSnapShots)
{
    s.Stats = new ObservableCollection<Stats>(s.Where(stat =>stat.Model.Agent != null));
}

因此,这将构建一个新的集合,其中包含 * are not * 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);
}
7uzetpgm

7uzetpgm5#

现在在observablecollection中有一个removeall方法,正如我在.net core 7中看到的那样-只是在任何人开始意外地重新发明轮子时提到它(我也一直在做-只是想帮忙)。

相关问题