我正在尝试找到一种优雅的方法来迭代列表,同时删除项目.
我知道这个解决方案.但我的条件更难:
问题:这可能吗?如果有,怎么样?
我有想法将对象标记为已删除/不活动.当我稍后再次迭代时,我将删除它们而不要求它们做事情.迭代将经常重复,这就是为什么每个对象在每次迭代时必须正好转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)
谢谢你的帮助!
你可以做的是在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)
代码来自我的另一个答案.它包含有关在对序列进行迭代时迭代序列的后果的其他切向信息,以及有关此代码及其设计决策含义的一些其他说明.