Excel 2003 VBAでIteratorを実装する(書きかけ)

はじめに

Excel 2003のVBAでデータを配列に格納してExcelやCSVにデータを出力するというプログラムを書いていたのですが、配列の扱いが非常に面倒なので、Iteratorを実装してみました。

やりたいこと

  • データのイメージとしては縦x横の表形式なので、それらのデータを格納できる変数を使用する
  • 2次元配列を使うのはめんどいので、1セットのデータ(Excelでいう1行データ)をCollection変数に格納し、さらにそれを配列に格納する(Collection変数にCollection変数を格納できないので)
  • データ数が不定で動的配列を使用したいが、配列の管理しなくて良いようにモジュール側で管理を行う

前提

  • 動的配列を使用する場合、要素数をユーザが拡張せねばならない
  • ExcelVBAで要素数を指定せずに使用できるCollection変数に、Collection変数を格納することができない
  • 処理の途中で要素数とか気にするのは面倒
  • 配列の宣言で指定するのは、要素数ではなくインデックス
  • インスタンス生成時に引数渡せない...

中身

データを格納するクラスモジュール

クラス名: DataRowSet.cls

Option Explicit
'#############################################################################
' まとまりのあるデータを行セット(例: オブジェクトの配列)として格納する
'
' @author satsv
'#############################################################################

Private DataRows() As Object           ' データ格納用
Private Last As Integer                ' 配列数

Private Sub Class_Initialize()
    Last = 0
End Sub

'#############################################################################
' 指定したインデックスに格納してあるデータを取り出す
'
' @param index  配列のインデックス
' @return       インデックスが指し示す要素
'#############################################################################
Public Function Item(ByVal index As Integer) As Object
    Set Item = IIf(index < Last, DataRows(index), Nothing)
End Function

'#############################################################################
' データを配列に格納し、配列要素数を更新
'
' @param objRecord  データ
'#############################################################################
Public Sub Add(ByRef objRecord As Object)
    ReDim Preserve DataRows(Last)
    Set DataRows(Last) = objRecord
    Last = Last + 1
End Sub

'#############################################################################
' 配列に格納されているデータ数を取得
'
' @return 配列要素数
'#############################################################################
Public Function GetLength() As Integer
    GetLength = Last
End Function

'#############################################################################
' Iteratorオブジェクトを生成し、自分自身を渡す
'
' @return Iteratorオブジェクト
'#############################################################################
Public Function Iterator() As Object
    Dim it As Object
    
    Set it = New DataRowSetIterator
    it.DataRowSet = Me
    Set Iterator = it
End Function
Iteratorモジュール

クラス名: DataRowSetIterator.cls

Option Explicit
'#############################################################################
' 行セット処理用Iterator
'
' @author satsv
'#############################################################################

Private RowSet As Object            ' 行セット格納用
Private CurrentCursor As Integer    ' 配列インデックス

Private Sub Class_Initialize()
    CurrentCursor = 0
End Sub

Private Sub Class_Terminate()
    Set RowSet = Nothing
End Sub

'#############################################################################
' プロパティ: 行セット格納用オブジェクトの設定(SetPropertyのみ)
'
' @return 行セット格納用オブジェクト
'#############################################################################
Public Property Let DataRowSet(ByRef Reference As Object)
    Set RowSet = Reference
End Property

'#############################################################################
' 次の要素があるかどうか
'
' @return 次の要素が存在すればTrue
'#############################################################################
Public Function HasNext() As Boolean
    HasNext = (CurrentCursor < RowSet.GetLength)
End Function

'#############################################################################
' 現在行(インデックスが指す要素)を返し、インデックスを次へ進める
'
' @return インデックスが指している要素
'#############################################################################
Public Function GetNext() As Object
    Dim rec As Object
    
    Set rec = RowSet.Item(CurrentCursor)
    CurrentCursor = CurrentCursor + 1
    
    Set GetNext = rec
End Function

Public Function HasPrevious() As Boolean

End Function

Public Function GetPrevious() As Object

End Function