ループで列挙しながらコレクションからアイテムを削除しようとする典型的なケースがあります。
List<int> myIntCollection = new List<int>();
myIntCollection.Add(42);
myIntCollection.Add(12);
myIntCollection.Add(96);
myIntCollection.Add(25);
foreach (int i in myIntCollection)
{
if (i == 42)
myIntCollection.Remove(96); // The error is here.
if (i == 25)
myIntCollection.Remove(42); // The error is here.
}
変更が行われた後の反復の開始InvalidOperationException
時に、基になるコレクションがいつ変更されるかを列挙子が気に入らないため、がスローされます。
繰り返しながらコレクションに変更を加える必要があります。これを回避するために使用できるパターンはたくさんありますが、どれも良い解決策を持っていないようです。
このループ内で削除しないでください。代わりに、メインループの後に処理する別の「リストの削除」を保持してください。
これは通常は良い解決策ですが、私の場合、アイテムを実際に削除するためのメインループがコードのロジックフローを変更するまで、アイテムを「待機中」として即座に削除する必要があります。
アイテムを削除する代わりに、アイテムにフラグを設定し、非アクティブとしてマークするだけです。次に、パターン1の機能を追加して、リストをクリーンアップします。
これは私のすべてのニーズに対応しますが、アイテムにアクセスするたびに非アクティブフラグをチェックするために、多くのコードを変更する必要があることを意味します。これは私の好みにはあまりにも多くの管理です。
どういうわけか、から派生したクラスにパターン2のアイデアを組み込み
List<T>
ます。このスーパーリストは、非アクティブフラグ、事後のオブジェクトの削除を処理し、非アクティブとしてマークされたアイテムを列挙型コンシューマーに公開しません。基本的には、パターン2(およびその後のパターン1)のすべてのアイデアをカプセル化するだけです。このようなクラスは存在しますか?誰かがこれのためのコードを持っていますか?それとももっと良い方法はありますか?
myIntCollection.ToArray()
代わりにアクセスmyIntCollection
すると問題が解決し、ループ内で削除できるようになると言われています。これは私には悪いデザインパターンのように思えますか、それとも問題ないのでしょうか?
詳細:
リストには多くのアイテムが含まれ、そのうちのいくつかのみを削除します。
ループ内では、追加、削除など、あらゆる種類のプロセスを実行するため、ソリューションはかなり一般的である必要があります。
削除する必要のあるアイテムは、ループ内の現在のアイテムではない可能性があります。たとえば、30アイテムループのアイテム10にいて、アイテム6またはアイテム26を削除する必要がある場合があります。このため、配列を逆方向に歩くことはできなくなります。; o(