ここでいう遅延実行とは
モジュール内のあちこちで使う変数で、最初に使う前の一回だけ初期化したいというとき、ありますね。
もちろんメインルーチンの先頭ででも初期化を呼べはいいのですが、イベントドリブンな処理ではそれすらあちこちに点在してしまいます。
そんなとき、使う側ではなく使われる側で、いざ使うときにそれが初めての使用だったら初期化する、必要がなければ初期化処理すらしない、といった書き方をすることがあります。
そんな状況で「実際に必要になった時点で行う」処理を、ここでは遅延実行と呼ぶことにします。
一時ブックでの例
ここでは、作業用の一時ブックを例にとってみます。
こんな感じの処理を想定しています。
Private mBook As New Workbook
Sub Main()
Dim i As Long
For i = 1 To 3
Select Case Rnd()
Case Is < 0.3
Call F
Case Is < 0.6
Call G
Case Else
'NOP
End Select
Next i
End Sub 'Main
''' F() や G() は、一時ブックを使用する例で中身に意味はない。
Sub F()
Debug.Print mBook.Worksheets(1).Range("F1").Address(External:=True)
End Sub
Sub G()
Debug.Print mBook.Worksheets(1).Range("G1").Address(External:=True)
End Sub
なお、これをこのまま実行するとエラーになります。
New Workbook と書いてでも、新しいブックは用意されないので mBook を用意する初期化処理がいるわけです。
そこで、モジュール変数 mBook はプロパティにして、Get の中で初期化がまだだったときだけ初期化処理を行う、とします。
Private mpBook As Workbook '原則として、プロパティ mBook 経由でアクセスする。
Private Property Get mBook() As Workbook
If mpBook Is Nothing Then
Set mpBook = Workbooks.Add()
End If
Set mBook = mpBook
End Property
Private Property Set mBook(ByVal NewVal As Workbook)
If mpBook Is NewVal Then
'NOP
ElseIf Not mpBook Is Nothing Then
Call mpBook.Close(SaveChanges:=False)
End If
Set mpBook = NewVal
End Property
Sub Main()
Dim i As Long
For i = 1 To 3
Select Case Rnd()
Case Is < 0.3
Call F
Case Is < 0.6
Call G
Case Else
'NOP
End Select
Next i
Set mBook = Nothing
End Sub 'Main
まあこの辺りは、クラスで書けよという声も聞こえてきそうですけれども。
応用範囲
他の応用例としては、動作の状況をテキストファイルに書き出すロガーなんかも似た感じで、簡易的に済ませたい場合はファイルの作成・オープンやヘッダ行の書き出しだけ Propery Get でやったりします。
ただ、今回の一時ブックと同様でクローズ処理が要るものはクラス管理した方が扱いが楽です。
とはいえ、初期化処理だけでも必要になった時だけ行いたいという場面はそこそこあります。
(追記) 後処理が不要で初期化処理が必要なものとしては、内容が固定の正規表現 RegExp のインスタンスなんてのもありますね。
そういう対象ごとにクラスに書き起こせばいいのですが、VBA は VB6 の伝統でクラスの管理をするのに階層化もできず作成したクラスがすべて同列に並んでしまうため、あまり数を増やしたくないのが実情です。
なので、初期化処理だけなら今回のようにプロパティにしてしまうのがいい落としどころかなと思います。
まとめ?
プロパティというとクラスが Public で持ってクラスの内外のインタフェースに使うもの、という印象がありますが、Private でも持てますし標準モジュールでも使うことができます。
変数のように使いたいけれどもアクセスするときにちょっとした判断処理を行いたい、というとき、 Property はなかなか役に立つのではないでしょうか。