Microsoft は、IEnumerable コレクションを変更する場合は、既存の IEnumerator オブジェクトを無効にすることを提案していますが、そのポリシーが特に役立つことはめったになく、迷惑になることもあります。IEnumerable/IEnumerator の作成者が、IEnumerator が変更なしで返されるデータと同じデータを返すことを妨げない方法でコレクションが変更された場合、例外をスローする必要があると感じる理由はありません。さらに進んで、可能であれば、列挙子が次の制約に従うことができる場合は、機能を維持することが望ましいと見なされることをお勧めします。
- 列挙の期間を通じてコレクション内にあるアイテムは、1 回だけ返される必要があります。
- 列挙中に追加または削除された各項目は、0 回または 1 回返されることがありますが、1 回を超えることはありません。オブジェクトがコレクションから削除され、再度追加された場合、最初は 1 つのアイテムに格納されていたが、新しいアイテムに入れられたと見なされる可能性があるため、列挙は正当に古いもの、新しいもの、または両方を返すか、またはどちらも返さない可能性があります。
VisualBasic.Collection クラスは、上記の制約に従って動作します。このような動作は非常に便利で、クラスを列挙して特定の基準を満たすアイテムを削除することができます。
もちろん、列挙中にコレクションが変更された場合に適切に動作するようにコレクションを設計することは、例外をスローするよりも必ずしも簡単ではないかもしれませんが、妥当なサイズのコレクションの場合、そのようなセマンティクスは、列挙子にコレクションをリストに変換させ、その内容を列挙させることによって取得できます。リスト。必要に応じて、特にスレッド セーフが必要ない場合は、列挙子によって返されるリストへの強い参照または弱い参照をコレクションに保持し、変更されるたびにそのような参照を無効にすることが役立つ場合があります。別のオプションは、コレクションへの「実際の」参照をラッパー クラスに保持し、内部クラスに存在する列挙子の数を保持させることです (列挙子は実際のコレクションへの参照を取得します)。列挙子が存在するときにコレクションを変更しようとすると、コレクション インスタンスをコピーに置き換えてから、その上で変更を行います (コピーは参照カウント 0 から始まります)。このような設計は、IEnumerator が Dispose されずに破棄されるシナリオを除いて、リストの冗長なコピーを作成することを回避します。そのシナリオでも、WeakReferences やイベントが関係するシナリオとは異なり、オブジェクトが必要以上に長く存続することはありません。