hex309’s diary

備忘録としてぼちぼちやります。VBAネタが多くなりそうです

Rangeオブジェクトと引数のカッコの話


先日、次のようなコードを見る機会が有りました。

Sub CopySample1()
    Range("A1").Copy (Cells(1, 2))
    Range("A2").Copy (Range("B2"))
End Sub

このコード、どちらもCopyメソッドの引数Destinationを指定しています。違いと言えば、貼り付け対象のセル(Rangeオブジェクト)をCellsプロパティで指定しているか、Rangeプロパティで指定しているかです。

このコードですが、「Range("A2").Copy (Range("B2"))」がエラーになります。

しかし、次のコードの場合、どちらもエラーにはなりません。

Sub CopySample2()
    Range("A1").Copy Cells(1, 2)
    Range("A2").Copy Range("B2")
End Sub

「CopySample1」プロシージャと「CopySample2」プロシージャの違いは、引数を「()」で囲んでいるかいないかです。

では、この「()」で囲んだことで何が起きているのか、次のコードで確認してみます。

Sub TypeNameTest()
    Debug.Print "Cells : " & TypeName((Cells(1, 1))), TypeName(Cells(1, 1))
    Debug.Print "Range : " & TypeName((Range("A1"))), TypeName(Range("A1"))
End Sub

TypeName関数は、引数に関する情報(主にデータ型)を返します。
実行結果は次のようになります。

Cells : Range Range
Range : Empty Range

TypeName関数の引数にCellsプロパティを使ったものとRangeプロパティを使ったものの2パターン。さらに、それぞれ引数そのものをカッコで囲んだものと囲まないものの2パターンです。
Cellsプロパティが両方とも「Range」を返しているのに対し、Rangeプロパティの方は、引数そのものをカッコで囲んだ方は「Empty」が返っています。
この「Empty」ですが、実はこのテストをする時にセルA1には何も入力されていません。何も入力されていないセルの値はEmptyなので、それが返っています。
念のため、セルA1に文字列を入力して、このコードを実行すると「String」が返りました。

ということは、「(Range("A1"))」と指定したときには、セルの値を評価している、ということになります。つまり「(Range("A1").Value)」ということですね。

となると、最初のコード(再掲します)で、「Range("A2").Copy (Range("B2"))」がエラーになったのも理解できます。

Sub CopySample1()
    Range("A1").Copy (Cells(1, 2))
    Range("A2").Copy (Range("B2"))
End Sub

「()」で囲んだことで、「Range("B2")」が、「Range("B2").Value」と解釈されたということです。となると、Copyメソッドの引数にはRangeオブジェクトを指定しなくてはなりませんから、エラーになるのも当然と言えます。
それに対して、「(Cells(1, 2))」の方は、「()」で囲んでもRangeオブジェクトを返していたので、エラーにはならなかった、ということです。