ArrayList
からアイテムを削除しようとしていますが、この例外が発生します。Collection was modified; enumeration operation may not execute.
何か案は?
foreach
の間にアイテムを削除していますか?単純に、できません。ここにはいくつかの一般的なオプションがあります。
List<T>
およびRemoveAll
を述部とともに使用しますインデックスによって逆方向に反復し、一致するアイテムを削除します
for(int i = list.Count - 1; i >= 0; i--) {
if({some test}) list.RemoveAt(i);
}
foreach
を使用し、一致するアイテムを2番目のリストに入れます。 2番目のリストを列挙し、最初のリストからそれらの項目を削除します(意味がわかる場合)
ここに例があります(タイプミスは申し訳ありません)
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);
}
「...」を、アイテムを削除するかどうかを決定する条件に置き換えます。
1つの方法は、削除するアイテムを新しいリストに追加することです。次に、それらのアイテムを削除して削除します。
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);
}
リストを反復処理するループ内でリストを変更しないでください。
代わりに、インデックスでfor()
またはwhile()
を使用して、リストを逆方向にたどってください。 (これにより、無効なインデックスを取得することなく削除できます。)
var foo = new List<Bar>();
for(int i = foo.Count-1; i >= 0; --i)
{
var item = foo[i];
// do something with item
}
何か不足していますか?私が間違っている場合、誰かが私を修正します。
list.RemoveAll(s => s.Name == "Fred");
Foreach()の代わりに、数値インデックスを使用してfor()ループを使用します。
この投稿で読んだいくつかのポイントに同意し、元の投稿とまったく同じ問題を解決するためにそれらをソリューションに組み込みました。
とはいえ、私が感謝したコメントは次のとおりです。
「.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;
}
ArrayList
を使用して、次のように試すこともできます
ArrayList arraylist = ... // myobject data list
ArrayList temp = (ArrayList)arraylist.Clone();
foreach (var item in temp)
{
if (...)
arraylist.Remove(item);
}