配列変数を値渡しにする
値渡しの配列引数
配列引数を値渡しにする方法
このときにも書いたとおり、通常、プロシージャの引数に配列を渡すとき、
Public Sub hogehoge(ByVal foo() As String)
みたいにすると、
こんなエラーが出る。
ところが、VBA四天王(だから、内わけはどうなっとるんだよw)の一人、id:imihito さん曰く、
引数の型をVariant型にすると、配列も値渡しで受け取ることができたりします
とのこと。
さらに、
オブジェクト型配列だと型情報が抜ける
とも。
へえ。いっぺんやってみよう。
Variant型引数にオブジェクト型の配列を渡してみる
メンドクサイので、2ついっぺんにやってみる。
リスト1 標準モジュール
Public Sub testDeclareObjectArgByVal() Dim Sh As Worksheet Set Sh = ThisWorkbook.Worksheets("Sheet1") Dim vtlTable(1) As New VirtualTable vtlTable(0).init Sh.Range("A1").CurrentRegion '……(1)' vtlTable(1).init Sh.Range("J1").CurrentRegion Call returnValue(vtlTable) '……(2)' End Sub Private Sub returnValue(ByVal targetVirtualTable As Variant) '……(3)' Dim i As Integer For i = LBound(targetVirtualTable) To UBound(targetVirtualTable) '……(4)' Debug.Print targetVirtualTable(i).valueOfCell(2, 2) Next Debug.Print TypeName(targetVirtualTable) '……(5)' End Sub
せっかくなので、
前回リニューアルしたVirtualTableクラス型の配列を使ってやってみた。
VirtualTableクラスのコードについてはコチラをどうぞ。
こんな表を用意して、
(1)からの2行
vtlTable(0).init Sh.Range("A1").CurrentRegion vtlTable(1).init Sh.Range("J1").CurrentRegion
で、initメソッドを用いて、A1セルのCurrentRegionをvtlTable(0)に、J1セルのCurrentRegionをvtlTable(1)に渡してそれぞれ初期化する。
(2)の
Call returnValue(vtlTable)
では、引数にVirtualTableクラス型の配列変数vtlTableを渡してreturnValueプロシージャを呼び出している。
returnValueプロシージャは、(3)からの7行
Private Sub returnValue(ByVal targetVirtualTable As Variant) '……(3)' Dim i As Integer For i = LBound(targetVirtualTable) To UBound(targetVirtualTable) '……(4)' Debug.Print targetVirtualTable(i).valueOfCell(2, 2) Next Debug.Print TypeName(targetVirtualTable) '……(5)' End Sub
(3)の
Private Sub returnValue(ByVal targetVirtualTable As Variant)
で、引数の型をVariant型にして、ByValキーワードを付けている。
見た目上、値渡しになっているが、その反面、見た目上は引数targetVirtualTableが配列変数だとは全く分からない。
このプロシージャ内では、まず(4)からの3行
For i = LBound(targetVirtualTable) To UBound(targetVirtualTable) Debug.Print targetVirtualTable(i).valueOfCell(2, 2) Next
で、VirtualTableクラスのインスタンスそれぞれが内部で保持している2次元配列(元は表)の2行2列目の値をイミディエイトに書き出し、それが終わったら、(5)の
Debug.Print TypeName(targetVirtualTable)
で、TypeName関数を用いて、引数として受け取ったtargetVirtualTableの型名をイミディエイトに出力する、という至って投げやりな処理を行う。
実行結果
おお! 3行目が「Object()」になっとる!
たしかに、もともとVirtualTable型であったという情報は失われているっぽい。
おわりに
この他にも、呼び出され側のプロシージャ(今回の場合はreturnValueプロシージャ)をコーディングするとき、targetVirtualTableの型が未確定なため、Intellisenseが全く効かず、非常に書きにくかった、ということも申し添えます。
わざわざ値渡しにする意義が今ひとつ見いだせなかった。