web-dev-qa-db-ja.com

コレクションが変更されました。列挙操作はArrayListで実行されない場合があります

ArrayListからアイテムを削除しようとしていますが、この例外が発生します。
Collection was modified; enumeration operation may not execute.

何か案は?

76
Ricardo

foreachの間にアイテムを削除していますか?単純に、できません。ここにはいくつかの一般的なオプションがあります。

  • List<T>およびRemoveAllを述部とともに使用します
  • インデックスによって逆方向に反復し、一致するアイテムを削除します

    for(int i = list.Count - 1; i >= 0; i--) {
        if({some test}) list.RemoveAt(i);
    }
    
  • foreachを使用し、一致するアイテムを2番目のリストに入れます。 2番目のリストを列挙し、最初のリストからそれらの項目を削除します(意味がわかる場合)

189
Marc Gravell

ここに例があります(タイプミスは申し訳ありません)

var itemsToRemove = new ArrayList();  // should use generic List if you can

foreach (var item in originalArrayList) {
  if (...) {
    itemsToRemove.Add(item);
  }
}

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

または、3.5を使用している場合、Linqは最初のビットをより簡単にします。

itemsToRemove = originalArrayList
  .Where(item => ...)
  .ToArray();

foreach (var item in itemsToRemove) {
  originalArrayList.Remove(item);
}

「...」を、アイテムを削除するかどうかを決定する条件に置き換えます。

23
Will

1つの方法は、削除するアイテムを新しいリストに追加することです。次に、それらのアイテムを削除して削除します。

8
ozczecho

forループを使用して逆方向に反復するのが好きですが、これはforeachと比較すると面倒です。私が好きな解決策の1つは、リストを逆方向にたどる列挙子を作成することです。これは、ArrayListまたはList<T>の拡張メソッドとして実装できます。 ArrayListの実装は次のとおりです。

    public static IEnumerable GetRemoveSafeEnumerator(this ArrayList list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;

                i = list.Count - 1;
            }

            yield return list[i];
        }
    }

List<T>の実装も同様です。

    public static IEnumerable<T> GetRemoveSafeEnumerator<T>(this List<T> list)
    {
        for (int i = list.Count - 1; i >= 0; i--)
        {
            // Reset the value of i if it is invalid.
            // This occurs when more than one item
            // is removed from the list during the enumeration.
            if (i >= list.Count)
            {
                if (list.Count == 0)
                    yield break;

                i = list.Count - 1;
            }

            yield return list[i];
        }
    }

以下の例では、列挙子を使用してArrayListから偶数の整数をすべて削除します。

    ArrayList list = new ArrayList() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    foreach (int item in list.GetRemoveSafeEnumerator())
    {
        if (item % 2 == 0)
            list.Remove(item);
    }
8
Joe B

リストを反復処理するループ内でリストを変更しないでください。

代わりに、インデックスでfor()またはwhile()を使用して、リストを逆方向にたどってください。 (これにより、無効なインデックスを取得することなく削除できます。)

var foo = new List<Bar>();

for(int i = foo.Count-1; i >= 0; --i)
{
  var item = foo[i];
  // do something with item
}
5
3Dave

何か不足していますか?私が間違っている場合、誰かが私を修正します。

list.RemoveAll(s => s.Name == "Fred");
4
KevinDeus

Foreach()の代わりに、数値インデックスを使用してfor()ループを使用します。

2
Seva Alekseyev

この投稿で読んだいくつかのポイントに同意し、元の投稿とまったく同じ問題を解決するためにそれらをソリューションに組み込みました。

とはいえ、私が感謝したコメントは次のとおりです。

  • 「.NET 1.0または1.1を使用している場合を除き、ArrayListの代わりにList<T>を使用してください。」

  • 「また、削除するアイテムを新しいリストに追加します。次に、それらのアイテムを調べて削除します。」 ..私の場合、新しいリストを作成し、有効なデータ値を入力しました。

例えば.

private List<string> managedLocationIDList = new List<string>();
string managedLocationIDs = ";1321;1235;;" // user input, should be semicolon seperated list of values

managedLocationIDList.AddRange(managedLocationIDs.Split(new char[] { ';' }));
List<string> checkLocationIDs = new List<string>();

// Remove any duplicate ID's and cleanup the string holding the list if ID's
Functions helper = new Functions();
checkLocationIDs = helper.ParseList(managedLocationIDList);

...
public List<string> ParseList(List<string> checkList)
{
    List<string> verifiedList = new List<string>();

    foreach (string listItem in checkList)
    if (!verifiedList.Contains(listItem.Trim()) && listItem != string.Empty)
        verifiedList.Add(listItem.Trim());

    verifiedList.Sort();
    return verifiedList;
}        
2
Brian Wells

ArrayListを使用して、次のように試すこともできます

ArrayList arraylist = ... // myobject data list

ArrayList temp = (ArrayList)arraylist.Clone();

foreach (var item in temp)
{
      if (...)
         arraylist.Remove(item);
}
1