我正在尝试寻找一种优雅的方式来迭代列表,同时删除项目。
I know this solution .但是我的条件更难一些:
- 此处所有单线程
- 迭代必须向前。
- 每个项目都必须恰好一次处理。
- 多个和随机项目可以在处理 1 个项目时移除。
- 项目是复杂且智能的对象。他们执行一个自定义方法,它可以决定删除某些项目(0 到全部)。
- (添加和插入也可以发生,但现在这并不重要,如果有办法同时处理,那就太好了)
问题:这可能吗?如果是,怎么办?
我想将对象标记为已删除/不活动。等我以后再迭代的时候,我就把他们去掉,不叫他们做事。迭代会经常重复,这就是为什么每个对象在每次迭代中都必须恰好转一圈。那行得通吗?
这就是我现在处理事情的方式。它并不完美,但我希望能为您提供提示。
伪代码:
class Foo
{
public void DoStuff()
{
// do other stuff
if (condition)
Kill(x); // should result in list.RemoveAt(x) somehow
}
}
class Program
{
[STAThread]
static void Main(string[] args)
{
List<Foo> list = new List<Foo>();
for (int i = 0; i < 15; i++)
list.Add(new Foo());
for (int i = 0; i < list.Count; i++)
list[i].DoStuff();
Console.ReadKey();
}
}
(这不是 XY 问题。我确定。多年来我一直在想这个问题,我决定最终找到一个可靠的解决方案。我正在为此使用 C# 工作。这不是恶作剧. 如果它像这样接缝,我很抱歉。)
感谢您的帮助!
最佳答案
您可以在此处使用 ObservableCollection
,以便迭代集合的代码可以检测集合在迭代时何时以及如何发生变异。通过使用 ObservableCollection
,迭代代码可以在当前索引之前添加项目时递增索引,或者在当前索引之前移除项目时递减索引。
public static IEnumerable<T> IterateWhileMutating<T>(
this ObservableCollection<T> list)
{
int i = 0;
NotifyCollectionChangedEventHandler handler = (_, args) =>
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
if (args.NewStartingIndex <= i)
i++;
break;
case NotifyCollectionChangedAction.Move:
if (args.NewStartingIndex <= i)
i++;
if (args.OldStartingIndex <= i) //note *not* else if
i--;
break;
case NotifyCollectionChangedAction.Remove:
if (args.OldStartingIndex <= i)
i--;
break;
case NotifyCollectionChangedAction.Reset:
i = int.MaxValue;//end the sequence
break;
default:
//do nothing
break;
}
};
try
{
list.CollectionChanged += handler;
for (i = 0; i < list.Count; i++)
{
yield return list[i];
}
}
finally
{
list.CollectionChanged -= handler;
}
}
代码取自this other answer of mine .它包含有关在改变序列时迭代序列的后果的其他切线信息,以及有关此代码及其设计决策含义的一些其他解释。
关于c# - 如何在同时删除项目的同时遍历列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24807799/