Created
August 7, 2012 10:26
-
-
Save dck-jp/3284359 to your computer and use it in GitHub Desktop.
a problem of "Dim As New" @ VBA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Public data As String |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Option Explicit | |
' VBAでコンパイル時に、Dim(特にDim As New)文が、 | |
' プロシージャ/メソッドの先頭に集められることによる弊害に関する検証 | |
'[背景] | |
' Dim As New文は、 | |
' 宣言と初期化が一度にできるので(他の言語とコーディングスタイルを合わせられるので) | |
' コードがすっきりするけど、 | |
' VBAでは、実行時(コンパイル後)に、Dim文が各プロシージャ/メソッドの先頭に再配置される仕様のため、 | |
' ループ内で使うと危ないよと@igetaさんから指摘を頂いたので色々メモ。 | |
'[以下のコードの概要] | |
' ・他のプログラミング言語同様、変数のスコープが小さく見える(*)ようループ内で変数を初期化 | |
' ・配列内には、異なるインスタンスを代入するのが目的。 | |
' (*)上述のVBAの仕様により、実際にはスコープは小さくならない。 | |
'[補足] | |
'※1 実行時(コンパイル後)には、Dim文は各プロシージャ/メソッドの先頭に位置するが、 | |
' 構文チェック(*)は、Dim文より後ろで変数が使われているかで判断される。 | |
' (*)コンパイル前に実行される | |
' | |
'※2 ループ内で構造体(Type)を初期化する場合、 | |
' 構造体の配列への代入は、DeepCopyのため、希望する動作になる。 | |
' | |
'※3 モジュール名を構造体と同じ名前にするとコンパイル時にエラーが出る(*) | |
' (*)コンパイラが、構造体とモジュールの区別をつけられないっぽい | |
' | |
'[私感] | |
' ・VBAでは、ループや条件分岐によって、変数のスコープが小さくなったりしないことを念頭に入れておくと安全? | |
' ・構造体を使うよりは、データクラスを使う方が、 | |
' 例外規定を覚える手間が減る(コーディングルールをシンプルに保てる)ので良いかも? | |
'safety | |
' :(マルチステートメント)を使って、初期化と宣言を一行で。 | |
Sub TestDimAndNew() | |
Dim class1s As New Collection | |
Dim i As Integer | |
For i = 0 To 2 | |
Dim cls1: Set cls1 = New Class1 | |
cls1.data = Str(i) | |
Call class1s.Add(cls1) | |
Next i | |
End Sub | |
'warning: all of items in class1s are same! | |
' Dim As New文を使って、初期化と宣言を一行で。 | |
Sub TestDimAsNew() | |
Dim class1s As New Collection | |
Dim i As Integer | |
For i = 0 To 2 | |
Dim cls1 As New Class1 | |
cls1.data = Str(i) | |
Call class1s.Add(cls1) | |
Next i | |
End Sub | |
'safety | |
'構造体を用いて同じことをやる | |
'構造体はCollectionsに代入できないので、配列で。 | |
Sub TestDimWithType() | |
Dim type1s(2) As TypeOne | |
Dim i As Integer | |
For i = 0 To 2 | |
Dim tp1 As TypeOne | |
tp1.data = Str(i) | |
type1s(i) = tp1 | |
Next i | |
End Sub |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Type TypeOne | |
data As String | |
End Type |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@igetaさんに、
「それちょっと嘘です。Dim As New は遅延初期化を行います。宣言した場所ではなく、メソッド呼び出しなどで、実際に最初に使われるときにインスタンス化されます」https://twitter.com/igeta/status/606611110465126400
という、ツッコミを頂いたので追補版を下記に作りました。
https://gist.github.com/dck-jp/24daacc002d6b5c03f33