p_chinのおっぱいブログ

UnityとPerlなど

foreachでコレクションを回す時に、回してるコレクションを操作してしまった時に起こるinvalidOperationException~

なんか、foreachの部分でエラーが出てびびった

// 実際にはhogeList.Clear使えばいいけどforeachで全要素を消したい時
foreach (hoge in hogeList) {
    hogeList.Remove(hoge);
}

これをやると、invalidOperationExceptionが投げられる

invalidOperationException: Collection was modified;

『コレクションが変更されてるぞ!』みたいな感じだ。

foreachでまさに回してるコレクションを削除したり入れ替えたりすると怒られるのだ

先輩達に聞いたら、C++やLLでは、これをやっても大丈夫な言語もあるらしい

 

全要素じゃないけど、任意の要素を複数消したい時はどうしよう?

現状、c#の機能だとこういうのよしなにしてくれないので

コレクションの要素を消す処理は、2段階に分けてやるしかないっぽい

以下の様な例でも、同じくinvalidOperationExceptionが発生する

// idが10以上のhogeオブジェクトを要素から削除する
foreach (hoge in hogeList) {
    if (hoge.id >= 10) {
        hogeList.Remove(hoge);
    }
}


// invalidOperationException!!!!!!!!!!!!!!!!!!!!

下のやり方ならば、要素のオブジェクトが何かユニークなメンバを持っている時に限って、エラーは出さないで、要素を消す事は出来る(DBっぽい)

// コレクションの要素を特定出来る値を取ってから一気に要素を消す
List<int> rmHogeIds = new List<int>();
foreach (hoge in hogeList) {
    if (hoge.id >= 10) {
        rmHogeIds.Add(hoge);
    }
}

//取得した要素毎のユニークなメンバリストから要素を突き止めて削除する!
foreach (id in hogeIds) {
    RemoveHogeListById(id, hogeList);
}

void RemoveHogeListById(int id, List<Hoge>) {
    // ここにidが一致したList消す処理書けばいいんじゃね
}

まとめ

金曜日の夜にこのエラーが出てテンパったけど

エラー文そのままじゃんって感じなので

『見た事無いエラー』ってだけで動揺しないでちゃんと読めよって感じだと思った

エラーの有無に限らず、今回の問題になった実装は分かりにくいかもねって思った