2019/11/16

オブジェクトの生成のやり方について

ExcelのみでDBを作り、SQLを使ってデータを出力する」のところで、以下のようなプログラムを紹介しました。
  1. Sub sql_01_A()
  2.  Dim cn As ADODB.Connection
  3.  Dim rs As ADODB.Recordset
  4.  Dim File_Name , Sql As String
  5.  Dim CurRow As Integer
  6.   File_Name = "c:¥Users¥User¥db.xlsx"  'DBのフルネーム。尚、このブック上(ThisWorkbook.FullName)でもOK
  7.   curRow =1
  8.   Set cn = New ADODB.Connection
  9.   Set rs = New ADODB.Recordset
  10.   cn.Provider = "MSDASQL"
  11.   cn.ConnectionString = "Driver={Microsoft Excel Driver (*.xls)};" & "DBQ=" & File_Name & "; ReadOnly=True;"
  12.   cn.Open
  13.   Sql = "SELECT name,date,hr FROM [Sheet4$] WHERE name='越後屋' "
  14.   rs.Open Sql , cn, adOpenStatic
  15.   Do Until rs.EOF
  16.   Sheets("Sheet3").cells(CurRow,1).Value = rs!name
  17.   Sheets("Sheet3"). cells(CurRow,2).Value = datevalue(rs!date)
  18.   Sheets("Sheet3"). cells(CurRow,3).Value = rs!hr
  19.   rs.MoveNext
  20.   CurRow = CurRow + 1
  21.   Loop
  22.   rs.Close
  23.   cn.Close
  24.  Set rs = Nothing
  25.  Set cn = Nothing
  26. End Sub

データベースからデータを取り出す内容ですが、これは以下のようにも書けます。(13行目以降は同じなので省略)
  1. Sub sql_01_B()
  2.  Dim cn As ADODB.Connection
  3.  Dim rs As ADODB.Recordset
  4.  Dim File_Name , Sql As String
  5.  Dim CurRow As Integer
  6.   File_Name = "c:¥Users¥User¥db.xlsx"  'DBのフルネーム。尚、このブック上(ThisWorkbook.FullName)でもOK
  7.   curRow =1
  8.   Set cn = CreateObject("ADODB.Connection")
  9.   Set rs = CreateObject("ADODB.Recordset")
10~11行目がNew演算子からCreateObject関数に代わっています。

また、以下のように、クラス型を宣言と同時にオブジェクト生成することもできます。
  1. Sub sql_01_D()
  2.  Dim cn As New ADODB.Connection
  3.  Dim rs As New ADODB.Recordset
  4.  Dim File_Name, Sql As String
  5.  Dim CurRow As Integer
  6.   File_Name = "c:¥Users¥User¥db.xlsx"
  7.   CurRow = 1
  8.   Set cn = CreateObject("ADODB.Connection") '不要
  9.   Set rs = CreateObject("ADODB.Recordset") '不要

また、2~3行目をクラス型ではなく、一般的なObject型として宣言することも出来ます。 この場合の10~11行目はCreateObject関数しか使用できません。
  1. Sub sql_01_C()
  2.  Dim cn As Object
  3.  Dim rs As Object
  4.  Dim File_Name, Sql As String
  5.  Dim CurRow As Integer
  6.   File_Name = "c:¥Users¥User¥db.xlsx"
  7.   CurRow = 1
  8.   Set cn = CreateObject("ADODB.Connection")
  9.   Set rs = CreateObject("ADODB.Recordset")

違うのは赤字の部分ですが、変数「cn」のみで整理をしてみます。(「rs」も同様と考えて下さい)
ABCD
参照設定 要(事前バインディング) 不要(実行時バインディング)
宣言 Dim cn
As ADODB. Connection
Dim cn
As ADODB. Connection
Dim cn
As New ADODB. Connection
Dim cn As Object
生成 Set cn =
New ADODB. Connection
Set cn =
CreateObject( "ADODB. Connection")
不要 Set cn =
CreateObject( "ADODB. Connection")
ここで、参照設定「要」というのは、「ExcelのみでDBを作り、SQLを使ってデータを出力する」の項で説明しましたが、以下の方法でExcelブックにライブラリを参照させる事です。
  


では、表の内容を確認していきましょう。
AとBとCは、事前に参照設定をするタイプである「事前バインディング」です。この場合は「Microsoft ActiveX Data Objects 2.8 Library」を参照設定しています。
その内、AとBはADODBのConectionクラス・ADODBのRecordsetクラスとして型宣言をし、その後でオブジェクトの生成を行っています。AとBは生成を行う方法が、New演算子を使用するかCreateObject関数を使うか、の違いです。
Cは、宣言時にNewを指定しておくと、その後でオブジェクトを最初に参照した時に新しいインスタンスが自動的に作成されるものです

一方、Dは「実行時バインディング」または「遅延バインディング」と呼ばれ、一般のObject型として型宣言した後、ADODBのConectionクラス・RecordsetクラスのオブジェクトとしてCreateObject関数で生成するものです。
実行時バインディングでは、New演算子は使用できません。

A~Cの方法のメリットの1つとしては、インテリセンス(コードをタイプしている途中で、メソッドやプロパティの候補を表示してくれる)が使用でき、また初期にオブジェクトの型を明示しているためコードが読み易く保守に優れます。また処理スピードにも差が出るようです。あるサイトによると、

高速 クラス型宣言を
Newで実施
クラス型宣言有+
Newで生成
クラス型宣言有+
CreateObject で生成
Object型宣言+
CreateObject で生成
低速

となるようです。(大量のループを回さない限り、それほど差は生まれません。コードが分かり易いのが一番です)

一方、Dの「実行時バインディング」の方は、メリットと言えるかどうか分かりませんが、比較的長期間に渡って使用できる、というのがあります。
Officeのバージョンが上がってくると、それに伴って参照設定するライブラリのバージョンも変化してきます。「事前バインディング」ではOfficeバージョンアップの都度、参照設定ライブラリのバージョンも気にする必要がありますが、「実行時バインディング」では気にしなくても良い、というものです。
しかし、バージョンが変化した際には参照設定ライブラリだけでなく、使えなくなる関数などコード自体の見直しも必要なはずですので、メリットと胸を張るほどでは無いかもしれません。

なお、Microsoftでは「B」の「クラス型宣言有+CreateObject」を推奨しています。理由は他のソフトとの整合性他によるものの様です。