AccessのVBAについて、ループ内でAs New使う時は注意ね!(別インスタンスにならないから)


連想配列のクラス使って検証しますん

この記事の例は Scripting.Dictionary を使うので、VBEの参照設定で Microsoft Scripting Runtime にチェックを入れる必要があります。

クラスをインスタンスする時、As Newはお手軽

ほいじゃあ連想配列使いましょうってなった時に、変数の宣言とインスタンスは…

Dim dic_ As Scripting.Dictionary
Set dic_ = New Scripting.Dictionary

…のように、まずは変数を用意して、その後にSetっていうのがよくあるパターン。

でも、下記のように宣言と格納をひとまとめにもできる。

Dim dic_ As New Scripting.Dictionary

As New ちょっと便利。

トラップ

さて、ループ内でAs Newを使うとどうなるか……。

Dim i_ As Long
For i_ = 1 To 3

    Debug.Print i_ & "のループいくよ!"

    '連想配列をインスタンスして中身入れる
    Dim dic_ As New Scripting.Dictionary
    dic_.Add i_, i_ & "ですが何か?"

    '連想配列の中身を確認
    Dim dic_key_ As Variant
    For Each dic_key_ In dic_
        Debug.Print dic_key_ & "の中身は" & dic_.Item(dic_key_)
    Next

Next

さて、上記の結果は…

1のループいくよ!
1の中身は1ですが何か?
2のループいくよ!
1の中身は1ですが何か?
2の中身は2ですが何か?
3のループいくよ!
1の中身は1ですが何か?
2の中身は2ですが何か?
3の中身は3ですが何か?

うーん…なんかちょっと変だね…(´・ω・`)
ループ内で別インスタンスしてる『つもり』なのに、前回のループ内容引き継いでしまってる

As Newを繰り返しても別インスタンスにはならないんでごわす。
別インスタンスにしたい時は Set する必要があるん。

Dim i_ As Long
For i_ = 1 To 3

    Debug.Print i_ & "のループいくよ!"

    '連想配列をインスタンスして中身入れる
    'As New ではなく、Setをしないと別インスタンスにならないから注意!
    Dim dic_ As Scripting.Dictionary
    Set dic_ = New Scripting.Dictionary

    dic_.Add i_, i_ & "ですが何か?"

    '連想配列の中身を確認
    Dim dic_key_ As Variant
    For Each dic_key_ In dic_
        Debug.Print dic_key_ & "の中身は" & dic_.Item(dic_key_)
    Next

Next

さて、上記の結果は…

1のループいくよ!
1の中身は1ですが何か?
2のループいくよ!
2の中身は2ですが何か?
3のループいくよ!
3の中身は3ですが何か?

As New の時と違うね。

As Newすれば別インスタンスが格納される という先入観で作ってしまうと間違いの元になりんす。

蛇足

AccessやVBAにはトラップがいっぱい…(´・ω・`)
いい意味で鍛えられるよ……ははは(´・ω・`)

バージョン

Windows10 Pro バージョン20H2 OSビルド19042.630
Access for Microsoft 365 MSO(16.0.13328.20334)32ビット