いままで結構VBAを書いてきたつもりだが
こんな基本的な? ことも知らなかった orz
通常、オブジェクト変数は 参照型になって Is 演算子 で 比較する。例えば 次のコード
Sub Test1()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Set ws1 = Worksheets(1)
Set ws2 = Worksheets(1)
Set ws3 = ws1
Debug.Print ws1 Is ws2 'True
Debug.Print ws1 Is ws3 'True
Debug.Print ws1 = ws2 'エラー
End Sub
ところが ExcelのRangeブジェクト変数は 少し挙動が違う
Sub Test2()
Dim c1 As Range
Dim c2 As Range
Dim c3 As Range
Set c1 = Range("A1:B2")
Set c2 = Range("A1:B2")
Set c3 = c1
Debug.Print c1 Is c2 'False
Debug.Print c1 Is c3 'True
Debug.Print c1 = c2 'エラー : 型が一致しません
End Sub
え? って なったのが
Debug.Print c1 Is c2 'False
の 部分。
調べると 「Rangeオブジェクトは取得されるごとに違うメモリアドレスに格納される」
??? 確認してみる!
Sub Test3()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Worksheets(1)
Set ws2 = Worksheets(1)
Debug.Print ObjPtr(ws1) = ObjPtr(ws2) 'Treu
End Sub
Sub Test4()
Dim c1 As Range
Dim c2 As Range
Set c1 = Range("A1:B2")
Set c2 = Range("A1:B2")
Debug.Print ObjPtr(c1) = ObjPtr(c2) 'False
End Sub
本当だ。。。。
色々 考察した結果、Rangeオブジェクトって その名の通り「範囲」を指定しているオブジェクトなんだと思います。 セルそのものを示しているのではなく、セルの範囲を指定するためのオブジェクトということです。
Worksheetオブジェクト変数が示す オブジェクトはWorkSheetそのものなので存在すればメモリ上に存在しますが、Rangeオブジェクトが示す オブジェクトはあくまでもセルの範囲なので 取得する毎に 生成され 使わなくなったら破棄される。そして同じセル範囲でも取得時毎に 新しいオブジェクトとして生成される。そう考えると挙動が説明できるように思います。 どうでしょう?
エラーコードの質問を受けると こういった気づきもあって 勉強になります。
質問って時に クイズみたいで なんか 楽しい 。
外部リンク
参:RangeオブジェクトはなぜIs演算子で比較できないのか
https://www.relief.jp/docs/excel-vba-is-operator-return-false-range.html
参:オブジェクト変数とは何か
https://excel-ubara.com/excelvba4/EXCEL_VBA_423.html
コメント