在C#中的新功能/ .NET 4.0的是,你可以改变你的foreach枚举没有得到例外。见保罗杰克逊的博客条目的 一个有趣的副作用并发的:从集合中删除项目,而枚举 的有关此变化信息

什么是做到以下几点最好的方法是什么?

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable)
    {
        item.Add(new item2)
    }
}

一般我使用IList作为高速缓存/缓存器,直到foreach的端部,但有更好的方法?

有帮助吗?

解决方案

在的foreach使用的集合是不可变的。这是由设计非常多。

作为它说 MSDN

  

foreach语句被用于   通过收集迭代得到   您想要的信息,但可以   不能用于添加或删除项目   从源头收集,以避免   不可预知的副作用。 如果您   需要从添加或删除项目   源集合,使用for循环。

提供在链路的交通过波科表明,这是允许在新的并发集合。

其他提示

请枚举的一个副本,在这种情况下使用一个IEnumerable扩展方法和枚举了它。这将在每一个内可枚举该枚举添加每一个元素的副本。

foreach(var item in Enumerable)
{
    foreach(var item2 in item.Enumerable.ToList())
    {
        item.Add(item2)
    }
}

如所提到的,但有一个代码示例:

foreach(var item in collection.ToArray())
    collection.Add(new Item...);

要说明Nippysaurus的回答是:如果你想为添加新项目列表,并希望同样枚举过程中处理新添加的项目太多,那么你可以只使用循环,而不是的的foreach 循环,问题解决:)

var list = new List<YourData>();
... populate the list ...

//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
    var entryToProcess = list[i];

    var resultOfProcessing = DoStuffToEntry(entryToProcess);

    if (... condition ...)
        list.Add(new YourData(...));
}

有关可运行的示例:

void Main()
{
    var list = new List<int>();
    for (int i = 0; i < 10; i++)
        list.Add(i);

    //foreach (var entry in list)
    for (int i = 0; i < list.Count; i++)
    {
        var entry = list[i];
        if (entry % 2 == 0)
            list.Add(entry + 1);

        Console.Write(entry + ", ");
    }

    Console.Write(list);
}

最后一个例子的输出:

0,1,2,3,4,5,6,7,8,9,1,3,5,7,9,

列表(15项) 结果0 结果1 结果2 结果3 结果4 结果5 结果6 结果7 结果8 结果9 结果1 结果3 结果5 结果7 结果,9

下面是你如何能做到这一点(快速和肮脏的解决方案,如果你的真正的需要这样的行为,您应该重新考虑你的设计或覆盖所有IList<T>成员和聚合源列表):

using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    public class ModifiableList<T> : List<T>
    {
        private readonly IList<T> pendingAdditions = new List<T>();
        private int activeEnumerators = 0;

        public ModifiableList(IEnumerable<T> collection) : base(collection)
        {
        }

        public ModifiableList()
        {
        }

        public new void Add(T t)
        {
            if(activeEnumerators == 0)
                base.Add(t);
            else
                pendingAdditions.Add(t);
        }

        public new IEnumerator<T> GetEnumerator()
        {
            ++activeEnumerators;

            foreach(T t in ((IList<T>)this))
                yield return t;

            --activeEnumerators;

            AddRange(pendingAdditions);
            pendingAdditions.Clear();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });

            foreach(int i in ints)
                ints.Add(i * 2);

            foreach(int i in ints)
                Console.WriteLine(i * 2);
        }
    }
}

LINQ 是非常有效的用于与集合杂耍。

您的类型和结构我不清楚,但我会尽量满足你的例子给我最大的能力。

这是你的代码看起来,对于每个项目,您要添加到该项目一切从自己的“可枚举”属性。这是非常简单的:

foreach (var item in Enumerable)
{
    item = item.AddRange(item.Enumerable));
}

作为一个更一般的例子,假设我们要遍历集合,并删除项目,其中某个条件是真的。避免foreach,使用LINQ:

myCollection = myCollection.Where(item => item.ShouldBeKept);

...添加基于每个现有物品的物品?没有问题:

myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));

您不能改变枚举集合而被列举的,所以你将收到或枚举后进行更改。

for循环是一个不错的选择,但如果你的IEnumerable收集未实现ICollection,这是不可能的。

或者:

1)复印收集第一。枚举复制的集合和枚举期间改变原有的集合。 (@tvanfosson)

2)保持改变的列表,并在枚举之后提交它们。

从性能的角度,最好的方法可能是使用一个或两个阵列。列表复制到一个数组,做阵列上操作,然后生成从阵列中一个新的列表。访问数组元素比访问列表项更快,一个List<T>T[]之间的转换可以使用一个快速“批量复制”的操作从而避免了相关联的访问的个别项目的开销。

例如,假设你有一个List<string>并希望在与T跟随一个项目“嘘”启动列表中的每个字符串,而所有以“U”开头的字符串中完全停止。最佳的做法可能会是这样的:

int srcPtr,destPtr;
string[] arr;

srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
  string st = arr[srcPtr];
  char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
  if (ch != 'U')
    arr[destPtr++] = st;
  if (ch == 'T')
    arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
  theList = new List<String>(arr); // Adds extra elements
  if (destPtr != arr.Length)
    theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
  Array.Resize(ref arr, destPtr);
  theList = new List<String>(arr); // Adds extra elements
}

这本来是有益的,如果List<T>提供从一个阵列的一部分构造的列表的方法,但我不知道这样做任何有效的方法的。尽管如此,对数组的操作是相当快的。值得注意的是,添加并从列表中删除项目并不需要“推”周围的其他物品的事实;每个项目被直接写入到阵列中的适当的位置。

您真的应该使用for()代替foreach()在这种情况下。

要添加到蒂莫的回答LINQ可以像这样使用,以及:

items = items.Select(i => {

     ...
     //perform some logic adding / updating.

     return i / return new Item();
     ...

     //To remove an item simply have logic to return null.

     //Then attach the Where to filter out nulls

     return null;
     ...


}).Where(i => i != null);

我已经写一个简单的步骤,但由于这样的性能将会降低

下面是我的代码片断: -

for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
                            {
                                foreach (Match match in reg.Matches(lines))
                                {
                                    var aStringBuilder = new StringBuilder(lines);
                                    aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
                                    lines[k] = aStringBuilder.ToString();
                                    tempReg = 0;
                                    break;
                                }
                            }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top