DOBON.NET どぼん!のVB道掲示板(プログラム)過去ログ

列挙操作とはなんでしょう?

P500以下ならお願いいたします。

下記の操作をすると
「追加情報 : コレクションが変更されました。列挙操作は実行されない可能性があります。」
という、エラーが出てしまいます。
試しに、Synchronizedというものを使ってみたのですが的をはずしていたようです。
このエラーは、For Each での中のみ起こります。それ以外の場所では正常に値を書き込めます。
どのように処理したらFor Eachno の中で正常な書き込みができるのでしょうか、よろしくお願いいたします。

hPole.Add("特記", "99")
hSyncPole = Hashtable.Synchronized(hPole)
    For Each vKey In hSyncPole.Keys
    hSyncPole("特記") = "10"
hSyncPole.Item("特記") = "10"
If hSyncPole.IsSynchronized Then
    MsgBox("synchronized")
Else
MsgBox("not synchronized")
End If
  Next
>P500以下ならお願いいたします。
>
>下記の操作をすると
>「追加情報 : コレクションが変更されました。列挙操作は実行されない可能性があります。」
>という、エラーが出てしまいます。
>試しに、Synchronizedというものを使ってみたのですが的をはずしていたようです。
>このエラーは、For Each での中のみ起こります。それ以外の場所では正常に値を書き込めます。
>どのように処理したらFor Eachno の中で正常な書き込みができるのでしょうか、よろしくお願いいたします。
>
>hPole.Add("特記", "99")
>hSyncPole = Hashtable.Synchronized(hPole)
>    For Each vKey In hSyncPole.Keys
>     hSyncPole("特記") = "10"
> hSyncPole.Item("特記") = "10"
> If hSyncPole.IsSynchronized Then
>     MsgBox("synchronized")
> Else
> MsgBox("not synchronized")
> End If
>  Next

.NETのクラスは知らないので的外れだったら済みません。でも、エラーで言われている通り、コレクションを変更しているのは明らかに思えます。

Synchronizedが入っていてとても見辛いのですが、列挙している間、つまり

For Each vKey In hSyncPole.Keys 〜 Next

の中で、hSyncPoleを書換えていますよね。
hSyncPole.Keysを列挙している間に、それ自身を変更しちゃっていいの?

私の感覚では、「vKeyも全然参照しないで、"特記"という固定のキーにアクセスするのなら、いったい何のためのループなの?」って感じなんですけど。

普通は、こんな風に使いますよねえ?

For Each vKey In hSyncPole.Keys
 〜 
 hSyncPole(vKey) = "xxx"
 〜 
Next
この発言は削除されました
私が書いてる間に、Kamaliさんが適切な回答をされていたので・・・
(無駄に長いのを修正しようと思って消してしまいました。すいません。)

今読み返して思ったのですが、もしかして Synchronized の方が本題ですか?


以下 For Each についてです
--------------------------------------------------
For Each は、いくつかのアイテムが登録されたコレクションについて、Index = 1〜Count まで全てについて操作を行う、という記述です。つまり、For i = 1 to Count ... Next i と同様です。For Each で指定されたオブジェクトにアイテムが参照されるので、指定したオブジェクト変数を使って直接操作が出来るという点が違います。カウンタ(iなど)が不要です。(For i = .. では コレクション.item(i) がアイテムの参照になっていますよね)また余談ですが、おそらく、For i = を使うよりいくらか動作が早いと思います。

で、このプログラムで何が起きてるか?というと、(1) コレクションオブジェクトに Key名 = "特記" で 99 という文字列をアイテム登録。(2) 同期のとれたラッパーを取得(これが本題でないなら気にしなくてよいです)。(3) コレクションに登録されているアイテムの、Key 名全て について For Each でアクセス。vKey に1つずつ Key名が入れられて処理されるループが開始。(4) 1回目のループは vKey = "特記"。(5)コレクションのアイテムのなかで、Key名 = "特記" のアイテムの値を 10という文字列に変更します。この時点で、「コレクションのKeys に For Each の参照ループが行われている」時に「コレクションの構成を変更した」のでエラーがでる、のだと思います。
皆様、ありがとうございました。
そもそも、for each の使い方があやふやだったことも判明してしまいましたが、
ようやっと、理解できました。

Synchronizedは、これを使ったらいけるかな?と淡い期待で、意味もわからず
入れてしまいました。

再度、皆様ありがとうございました。
hCopyPole = hPole(vRoop).Clone
For Each vKey In hCopyPole.Keys
If hPole(vRoop).Item(vKey) = "" Then
hPole(vRoop)(vKey) = hPole(vRoop - 1)(vKey)
End If
Next vKey

やはり、Itemを書き換えるとエラーになってしまうので、hCopyPoleというコピーを作成しまわしてみました。
列挙をやめて直接 For i = ... で取得するのは試してみました?
Hashtableは使った事がないので、Index の開始が 0からか1からかわかりませんが(汗

For i = 0 to htbTest.Keys.Count -1
hstbTest( htbTest.Keys(i) ) = (値の変更)
Next i

の様な記述が出来ると思います。For Each は列挙開始から終了まで参照専用ですが、こちらはその都度直接参照に行くので(ほんの少しは遅いかもしれませんが)エラーにはならないと思います。(Index の開始が 1からだと 1 to ...Count にしてください)

----------------------------------------------
※VB.net になっても Index の開始が 1 から(VBコレクション系)と0から(その他と .net Framework のクラス?なのかな)が混在しているッスよね〜覚えられんッス(T^T
すいません。Hashtable, Hashtable.Keys は ICollection でした。この方法は出来ませんね。VBのコレクションしか使っていないので、間違えました。

DOBON.NET | プログラミング道 | プログラミング掲示板