在 C# 中创建消耗 foreach

本文关键字:foreach 创建 | 更新日期: 2023-09-27 18:21:26

有没有办法在 C# 中创建消耗foreach循环?基本上循环浏览一个收藏品并同时消耗它们?

简单的英语来说:不要只是循环浏览元素,而是从集合中删除项目,用它做一些事情,然后转到下一个。

编辑 我忽略了提到我正在使用生产消费模式,这就是为什么我想要一个消费模式。这里的大多数答案对于我在编辑之前描述的简单情况都是完全有效的,尽管我想要的在我的答案中有所描述

在 C# 中创建消耗 foreach

使用Stack(后进先出(或Queue(先进先出(。

一个很好的例子是这个"递归"队列,它列出了目录中的所有文件。

正如您的问题的评论中所指出的,使用堆栈或队列是"处理然后删除"模式的最佳选择。如果由于某种原因您不想使用这些专用类,您可以使用普通List执行以下操作:

var items = new List<Item>() {item1, item2, item3};
while(items.Count > 0)
{
    ProcessItem(item[0]);
    items.RemoveAt(0);
}

但是你不能做的是修改foreach循环中的集合,正如 StepUp 的答案中所解释的那样。

foreach中使用的集合是不可变的。这是设计使然。

MSDN 说:

foreach 语句用于循环访问集合以获取所需的信息,但不能用于在源集合中添加或删除项以避免不可预知的副作用。如果需要在源集合中添加或删除项,请使用 for 循环。

更新 0.0:可以使用for循环来编辑集合: 若要将项目添加到集合,可以使用for循环:

List<string> coll = new List<string>() { "1", "2", "3", "4", "5" };
for (int i = coll.Count-1; i>=0 ; i--)
{ 
   /* You can assign value to an item:
    coll[i] = "";       
   You can add an item to the collection:
   coll.Add(i.ToString());*/
   coll.RemoveAt(i);
   //or coll.Remove("your string value to delete");
}

不完全是"消耗foreach",但可能您正在寻找的是TPL数据流。

例如,请参阅:https://leanpub.com/tpldataflowbyexample/read 或 MSDN:创建数据流管道或 MSDN:实现生产者/使用者方案

一个非常非常基本的例子可以如下所示:

  var actionBlock = new ActionBlock<int>(n => Console.WriteLine(n));
             for (int i = 0; i < 10; i++) {
                 actionBlock.Post(i);
             }
             Console.WriteLine("Done");

您还可以链接多个区块,以创建更复杂的使用分叉等消费策略。您还可以为步骤定义不同的调度程序类型。

对于非常简单的方案,这可能过大,但 TPL 是一个很好的缩放解决方案,可以对数据流的外观进行大量控制。

如 StepUp 的答案中所述,foreach 循环中使用的集合是不可变的。但是,可以使用BlockingCollection并使用在循环访问集合项时使用集合项的GetConsumingEnumerable来执行类似的事情。鉴于我的收藏是并发产品消费计划的一部分(我在我的问题中忽略了提及(,这更适合我。在更简单的情况下,尽管其他答案,使用堆栈或队列更合适,或者简单的循环,从集合的末尾循环到开始并在途中删除项目(删除的开始到结束循环将跳过项目或最终进入IndexOutOfBounds Exception