Listクラスでの失敗

List<T>クラスは非常に便利なクラスです。配列のように大きさが決まっていないので、要素が増えたり減ったりするものを扱うのに適しています。
トランプゲームを作るときにカード一つ一つにint型のIDを割り当てています。一度に複数のカードを出すといったときにList<int>で複数のカードを表すと扱いが簡単です。リストの分だけ処理をforeachで行えば良いからです。

Listを使うときに失敗したことをメモしておきます。たまに「あれ、どうなってるんだっけ?」となるもので、先日テストコードを書きました。

Listを引数に渡したとき、内部で要素を足したり消したりすると影響が残る


このスクリプトをUnityで適当なゲームオブジェクトにアタッチしてみた結果は次のようになりました。

見てもらえば大体わかると思いますが、ListAddやListRemoveに渡したリストの内容が変わります。List<T>はクラスなので、参照型ということですね。参照型を引数に渡したときの挙動は気を付けないと、バグになりやすいです。

リストのループ内でリストを変更してはいけない


このスクリプトをUnityで適当なゲームオブジェクトにアタッチしてみた結果は次のようになりました。

この例は実行するとエラーを起こしますが、コンパイルは通ります。これはforeachループ内でリストに変更をしていることが問題です。(list.Remove(2)のところです。)
実行すればわかるバグですが、この例よりも複雑なことをする場合には意外と気づきにくいバグになります。
リストの要素を一つずつ検査していって、ある条件になっているものを除きたいというときに同じループ内で決してしまうということをやってしまうとエラーになります。RemoveAllメソッドを使うか、いったん削除対象を別のリストに入れてからそのリストのループ内で元のリストの要素を消していくことになります。