LoginSignup
2
2

More than 5 years have passed since last update.

簡易的な遅延実行には、Property Get を使おう

Last updated at Posted at 2019-03-24

ここでいう遅延実行とは

モジュール内のあちこちで使う変数で、最初に使う前の一回だけ初期化したいというとき、ありますね。
もちろんメインルーチンの先頭ででも初期化を呼べはいいのですが、イベントドリブンな処理ではそれすらあちこちに点在してしまいます。
そんなとき、使う側ではなく使われる側で、いざ使うときにそれが初めての使用だったら初期化する、必要がなければ初期化処理すらしない、といった書き方をすることがあります。

そんな状況で「実際に必要になった時点で行う」処理を、ここでは遅延実行と呼ぶことにします。

一時ブックでの例

ここでは、作業用の一時ブックを例にとってみます。
こんな感じの処理を想定しています。

TempraryBook_v1
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 の中で初期化がまだだったときだけ初期化処理を行う、とします。

TempraryBook_v2
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 はなかなか役に立つのではないでしょうか。

2
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2