如何在同时删除项目时迭代列表?

Bit*_*lue 4 c# iteration list

我正在尝试找到一种优雅的方法来迭代列表,同时删除项目.
我知道这个解决方案.但我的条件更难:

  • 所有单线程都在这里
  • 迭代必须是前进的.
  • 每个项目必须只处理一次.
  • 在处理1个项目时,可以删除多个和随机项目.
  • 物品是复杂而聪明的物品.它们执行自定义方法,并且可以决定删除某些项目(0到all).
  • (添加和插入也可能发生,但是现在这并不重要,如果有办法同时处理这个,那就太好了)

问题:这可能吗?如果有,怎么样?


我有想法将对象标记已删除/不活动.当我稍后再次迭代时,我将删除它们而不要求它们做事情.迭代将经常重复,这就是为什么每个对象在每次迭代时必须正好转1圈.那会有用吗?


这就是我现在处理事情的方式.它并不完美,但会给你提示我希望得到的东西.

伪代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)


(这不是一个XY问题.我很确定.我已经把这个放在我脑海里多年了,我决定最终找到一个可靠的解决方案.我正在用C#工作.这不是恶作剧.我对不起,如果它接缝那么.)

谢谢你的帮助!

Ser*_*rvy 6

你可以做的是在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

代码来自我的另一个答案.它包含有关在对序列进行迭代时迭代序列的后果的其他切向信息,以及有关此代码及其设计决策含义的一些其他说明.