2

.NET コレクションを列挙するとき、MSDN は次のように述べています。

コレクションが変更されない限り、列挙子は有効なままです。要素の追加、変更、または削除などの変更がコレクションに加えられた場合、列挙子は回復できないほど無効になり、その動作は未定義になります。

「回復不能な無効化」とは正確にはどういう意味ですか?

たとえば、左右の子への参照と親への参照の両方を持つ二分木を考えてみましょう。このようなツリーでは、ツリー内の次のノードを簡単に見つけることができるため、ツリー内をナビゲートするには、ツリー内の 1 つのノードへの 1 つの参照で十分です。

そのツリーで、他のノードを削除するとします (おそらく、現在座っているノードは削除しません)。それでも、列挙子を無効にする必要がありますか? ここではマルチスレッド操作について話しているのではなく、単一のスレッドがループを実行し、ループ本体内のコレクションを変更していることに注意してください。

この「法則」は本当に、列挙子が続行できたとしても続行すべきではないという法則ですか?

4

2 に答える 2

8

この「法則」は本当に、列挙子が続行できたとしても続行すべきではないという法則ですか?

個人的には、理論的には継続できるとしても、列挙子にスローさせることは良い習慣だと思います。

コレクションを変更するコードを foreach ループ内にうっかり入れてしまうことがよくあります。これを行わないと、開発者が現在テストしている特定のインスタンスでスローされない可能性がありますが、別のランタイム条件によって簡単にスローされる可能性があります。

常にスローすることで、開発者はコードをフレームワークのコレクションや列挙と同じように扱う必要があります。これは、ライブラリを扱うときの驚きのレベルを減らすため、良いことだと思います。

于 2010-01-04T18:40:20.777 に答える
2

標準コレクション列挙子の実装により、それが法律になります。それらが作成されると、コレクション オブジェクトからプライベートな「バージョン」整数がコピーされます。コレクションを変更すると、そのバージョンがインクリメントされます。イテレータ メソッドはバージョンを比較し、不一致がある場合はそれをスローします。それを回避する方法はありません。

ただし、列挙中にコレクションを変更できるコレクション クラスが 1 つあります: Microsoft.VisualBasic.Collection。VB6 Collection クラスとの互換性を維持するために、これを行う必要がありました。それがどのように行われるかを確認するために、それを見てみたいと思うかもしれません。IIRC では、すべてのイテレータで WeakReference を保持し、コレクションが変更されたときにイテレータを更新します。もちろん、これは絶対確実ではありません。要素を削除して再度追加すると、同じオブジェクトが 2 回列挙される可能性があります。安いわけでもありません。

于 2010-01-04T18:58:27.713 に答える