参照設定を行いクラスの型宣言を行う方が速い
VBAでクラスを利用する場合に、変数宣言時に型を書く方法と書かない方法の2通りがあります。型を書く場合は、事前に参照設定で対象のライブラリにチェックをつけておく必要があります。そうすることで変数宣言時に型として指定することができます。
型を書かない場合は、変数名だけを書くか、もしくは実際のクラスの型ではなくObject型変数として定義することもできます。
いずれの場合も、変数宣言のあとでNewやCreateObject関数を利用して対象クラスのオブジェクトを生成する必要があります。
結論から言えば、参照設定を事前に行い、変数宣言時にデータ型としてクラスを指定した上で、対象クラスをNewでオブジェクト作成する方法が処理速度は一番速くなります。ただし、処理速度の差が体感できるのは100万件以上のような大量のデータを扱う場合になります。そうでない数回程度であればほとんど差はありません。
なお、参照設定はVBAの画面で、ツールメニュー→参照設定、でダイアログが開きます。
クラス利用時の型宣言は4通り
先に書いた内容をコードで示します。コードでは主に4つの書き方が出来ます。例としてFileSystemObjectを使います。他のクラスを使った場合も同じです。
以下の1つ目と2つ目の参照設定+型宣言がある書き方を事前バインディング、3つ目と4つ目のクラス型の型宣言をしない書き方を実行時バインディングや遅延バインディングと言います。
言葉自体はここでは気にしなくていいです。
クラスの型宣言+New
1 2 |
Dim fso As FileSystemObject Set fso = New FileSystemObject |
クラスの型宣言+CreateObject
1 2 |
Dim fso As FileSystemObject Set fso = CreateObject("Scripting.FileSystemObject") |
クラスの型宣言なし+CreateObject
1 2 |
Dim fso Set fso = CreateObject("Scripting.FileSystemObject") |
Object型宣言+CreateObject
1 2 |
Dim fso As Object Set fso = CreateObject("Scripting.FileSystemObject") |
Object型の変数宣言ではオブジェクトが設定されることのみを定義しており、まだどういうクラスのオブジェクトが設定されるのか不明のため「クラスのオブジェクトが入る予定」の状態です。
そのため事前にはクラスが分かっていない状況です。
検証用ソースコード
実際にどれぐらいの差があるのかを検証します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
Sub VariableTypeSpeedTest2() Dim tmStart As Double Dim tmEnd As Double Dim tmDiff As Double Dim fso1 As FileSystemObject Dim fso2 As FileSystemObject Dim fso3 Dim fso4 As Object Dim i Dim b '// 1. 型宣言あり+New tmStart = Timer For i = 0 To 100000 Set fso1 = New FileSystemObject b = fso1.FileExists("C:\aa.txt") Next tmEnd = Timer tmDiff = tmEnd - tmStart Debug.Print "1.型宣言あり+New:" & tmDiff & "秒" '// 2. 型宣言あり+CreateObject tmStart = Timer For i = 0 To 100000 Set fso2 = CreateObject("Scripting.FileSystemObject") b = fso2.FileExists("C:\aa.txt") Next tmEnd = Timer tmDiff = tmEnd - tmStart Debug.Print "2.型宣言あり+CreateObject:" & tmDiff & "秒" '// 3. 型宣言なし+CreateObject tmStart = Timer For i = 0 To 100000 Set fso3 = CreateObject("Scripting.FileSystemObject") b = fso3.FileExists("C:\aa.txt") Next tmEnd = Timer tmDiff = tmEnd - tmStart Debug.Print "3. 型宣言なし+CreateObject:" & tmDiff & "秒" '// 4. Object型宣言あり+CreateObject tmStart = Timer For i = 0 To 100000 Set fso4 = CreateObject("Scripting.FileSystemObject") b = fso4.FileExists("C:\aa.txt") Next tmEnd = Timer tmDiff = tmEnd - tmStart Debug.Print "4. Object型宣言あり+CreateObject:" & tmDiff & "秒" End Sub |
実行結果(コンパイルせずに実行)
1. 型宣言あり+New:2.3125秒
2. 型宣言あり+CreateObject:3.1015625秒
3. 型宣言なし+CreateObject:3.703125秒
4. Object型宣言あり+CreateObject:3.6953125秒
この結果からも参照設定+型宣言ありの方が速いことが分かります。ただし、参照設定をしていてもNewとCreateObjectでは差が出ています。これはよく言われることですがCreateObject関数が遅いことが原因です。
CreateObjectは引数に文字列でクラス名を指定する必要があることからどうしても文字列処理が発生することや、オブジェクトを作成する先も指定可能なため処理が冗長化していることもあり、その分も遅延の原因になります。
結果として、型宣言がない場合ほどではありませんがかなりの遅延になっています。このことからも、参照宣言+型宣言あり+Newが一番処理速度は速いことが分かります。
1 2 |
Dim fso As FileSystemObject Set fso = New FileSystemObject |
多くの場合はこの書き方での実装が可能と思われます。なお、この検証ではコンパイルを行わずに行っています。
事前バインディングについて「コンパイルを行うから速い」と説明しているサイトもありますが、それだけが速い理由ではなく上記の遅延原因を明示するためにあえてコンパイルしていません。
もちろんコンパイルするとさらに速くなります。以下はコンパイルを行った場合の実行結果ですが、Newの場合はコンパイルをしている方がしていないときよりも速くなっています。
それとは逆にCreateObjectを行うNo.2, 3, 4は、実行時に型判定されるためコンパイル有無が処理速度に影響していないことが分かります。
実行結果(コンパイルを行って実行)
1. 型宣言あり+New:2.18902587890625秒
2. 型宣言あり+CreateObject:3.06097412109375秒
3. 型宣言なし+CreateObject:3.69500732421875秒
4. Object型宣言あり+CreateObject:3.81500244140625秒
参照設定をした方が速い理由
事前バインディングと実行時バインディングについては以下のMicrosoftのヘルプに記載があります。
https://msdn.microsoft.com/ja-jp/library/cc343951.aspx
型宣言を事前に行った方が速いのは、事前バインディングと実行時バインディングの説明そのままになるのですが、型宣言をしていない場合は変数の型が実行時まで分からないことにより、処理の度に型判定を行うことになります。
型宣言を行っている場合は当然型判定は必要ありません。その差が遅延に繋がっています。