2

まさにこの形式でまだ尋ねられていないことに驚いています。

データ ソースの反復処理 (および yield return ステートメントの使用) に基づいて生成された IEnumerable がある場合、Enumerator を介して生成された Enumerator を介したアクセス後にソースが変更されたことを検出するにはどうすればよいですか? GetEnumerator 呼び出し?

ここに奇妙な部分があります。私はマルチスレッドではありません。これは単純なはずなので、私の質問にはどこかに欠陥があると思います。. . ソースがいつ変更され、イテレータが古くなったか知りたいだけです。

どうもありがとう。

4

4 に答える 4

5

この情報を追跡するには、列挙子を自分で作成する必要があります。少なくともyield return;、独自の種類の変更追跡を使用する必要があります。

たとえば、ほとんどのフレームワーク コレクション クラスは、「バージョン」番号を保持しています。列挙子を作成するとき、そのバージョン番号のスナップショットを保持し、MoveNext(). 電話をかける前に同じチェックを行うことができますyield return XXX;

于 2011-09-13T02:18:08.303 に答える
3

.NET BCL のほとんどのコレクション クラスは、変更の追跡にバージョン属性を使用します。つまり、列挙子はバージョン番号 (整数) で構築され、バージョン番号の元のソースが反復ごとに同じであることを確認します ( movenext が呼び出されたとき)。コレクションは、変更が行われるたびに version 属性をインクリメントします。この追跡メカニズムはシンプルで効果的です。

私が見た他の2つの方法は次のとおりです。

コレクションに、未処理の列挙子への弱参照を含む内部コレクションを保持させる。コレクションに変更が加えられるたびに、まだ生きている各列挙子が無効になります。

または、コレクション ( INotifyCollectionChanged ) にイベントを実装し、列挙子でそのイベントに登録するだけです。発生した場合は、列挙子を無効としてマークします。このメソッドは実装が比較的簡単で汎用的であり、多くのオーバーヘッドはありませんが、コレクションがイベントをサポートする必要があります

于 2011-09-13T02:29:52.983 に答える
1

Microsoft は、IEnumerable コレクションを変更する場合は、既存の IEnumerator オブジェクトを無効にすることを提案していますが、そのポリシーが特に役立つことはめったになく、迷惑になることもあります。IEnumerable/IEnumerator の作成者が、IEnumerator が変更なしで返されるデータと同じデータを返すことを妨げない方法でコレクションが変更された場合、例外をスローする必要があると感じる理由はありません。さらに進んで、可能であれば、列挙子が次の制約に従うことができる場合は、機能を維持することが望ましいと見なされることをお勧めします。

  1. 列挙の期間を通じてコレクション内にあるアイテムは、1 回だけ返される必要があります。
  2. 列挙中に追加または削除された各項目は、0 回または 1 回返されることがありますが、1 回を超えることはありません。オブジェクトがコレクションから削除され、再度追加された場合、最初は 1 つのアイテムに格納されていたが、新しいアイテムに入れられたと見なされる可能性があるため、列挙は正当に古いもの、新しいもの、または両方を返すか、またはどちらも返さない可能性があります。

VisualBasic.Collection クラスは、上記の制約に従って動作します。このような動作は非常に便利で、クラスを列挙して特定の基準を満たすアイテムを削除することができます。

もちろん、列挙中にコレクションが変更された場合に適切に動作するようにコレクションを設計することは、例外をスローするよりも必ずしも簡単ではないかもしれませんが、妥当なサイズのコレクションの場合、そのようなセマンティクスは、列挙子にコレクションをリストに変換させ、その内容を列挙させることによって取得できます。リスト。必要に応じて、特にスレッド セーフが必要ない場合は、列挙子によって返されるリストへの強い参照または弱い参照をコレクションに保持し、変更されるたびにそのような参照を無効にすることが役立つ場合があります。別のオプションは、コレクションへの「実際の」参照をラッパー クラスに保持し、内部クラスに存在する列挙子の数を保持させることです (列挙子は実際のコレクションへの参照を取得します)。列挙子が存在するときにコレクションを変更しようとすると、コレクション インスタンスをコピーに置き換えてから、その上で変更を行います (コピーは参照カウント 0 から始まります)。このような設計は、IEnumerator が Dispose されずに破棄されるシナリオを除いて、リストの冗長なコピーを作成することを回避します。そのシナリオでも、WeakReferences やイベントが関係するシナリオとは異なり、オブジェクトが必要以上に長く存続することはありません。

于 2011-09-13T14:52:12.097 に答える