以下の内容はhttps://thom.hateblo.jp/entry/2017/04/16/021320より取得しました。


VBA Rangeオブジェクトはシートを操作するエージェント

VBAで扱える代表的なExcelのオブジェクトにWorkbook、Worksheet、Rangeなどがある。

  • ひとつのブックにはひとつのWorkbookオブジェクトが対応している。
  • ひとつのシートにはひとつのWorksheetオブジェクトが対応している。

ではひとつのセルに対応する固有のオブジェクトは?



5秒、4、3、2、1、はい。




Cellと答えたあなた。ぶっぶー。

Rangeと答えたあなた。ぶっぶっぶー。

実はひとつのセルに対応する固有のオブジェクトは存在しないってのが答え。

「固有の」ってとこがミソ。

まずCellというオブジェクトは存在せず、WorksheetオブジェクトのCellsプロパティが返すのは全セルを表すRangeオブジェクトである。このことは以下の記事で詳しく書いた。
thom.hateblo.jp

そもそもセルがいくつあるか考えてみよう。Excel2007以降、扱えるセル範囲は16,384桁1,048,576行となっている。つまり単純に掛け算して約170個のセルが存在することになる。これらにそれぞれ対応するオブジェクトが存在するとしたらExcelだけでPCのメモリを食いつぶしてしまう。

じゃあいったいRangeとは何なのか。

Rangeとはシートを操作するエージェント(代理人)のようなものである。

ひとつ実験をしてみよう。
オブジェクトが一致するかどうかを比較する方法として、Is演算がある。
もしSheets(1).Range("A1")がひとつの固有なRangeオブジェクトを返すなら、以下はTrueになるはずだ。

Sub hoge()
    MsgBox Sheets(1).Range("A1") Is Sheets(1).Range("A1")
End Sub

実際に実行してみるとわかるが、上記のマクロはFalseになる。
同じセルを指してるのになんで!?と思うかもしれないけれど、これがエージェントと表現した所以。

つまりRangeとはWorksheetに代わってセルを操作する代理人(エージェント)である。

こんな風に、同じA1セルを管理していても、同じエージェントであるとは限らない。
f:id:t-hom:20170416013829p:plain

だからこうやってIsで比較すると。
f:id:t-hom:20170416014104p:plain

違うんだ!と。
f:id:t-hom:20170416014354p:plain

つまりWorksheetオブジェクトのRangeプロパティは評価するたびに新しいRangeオブジェクトを生成しているのだ。

ちなみに変数に入れてあげれば当然一致する。

Sub hoge()
    Dim r As Range
    Set r = Sheets(1).Range("A1")
    MsgBox r Is r
End Sub

これはTrue。

ここで面白いのが、以下のようにOffsetをかますと不一致になるという点。

Sub hoge()
    Dim r As Range
    Set r = Sheets(1).Range("A1")
    MsgBox r Is r.Offset(0, 0)
End Sub

Offset(0, 0)ということは実質的におなじセルを指してるのに不一致。
つまりOffsetは内部で新しいRangeエージェントを作って返してるようだ。

以前クラスモジュール内で自身と同じ型の別インスタンスを返すという処理をやったけど、まさにあれと同じ。
thom.hateblo.jp

Offsetプロパティは内部でRangeをNewして返してるイメージ。実際に中身見たわけではないので具体的な実装は知らないけど。

なお、同じセルを指しているかどうかを調べたかったらAddressプロパティをイコールで比較してあげればよい。

Sub hoge()
    Dim r As Range
    Set r = Sheets(1).Range("A1")
    MsgBox r.Address = r.Offset(0, 0).Address
End Sub

これはTrueになる。

ちなみにシートの場合はどうかというと、

Sub hoge()
    MsgBox Sheets(1) Is Sheets(1)
End Sub

このように普通にIsで比較してもTrueが返される。

以下のように表現を変えてみても同じくTrue。

Sub hoge()
    MsgBox Sheets(1) Is Sheets("Sheet1")
End Sub

以下のように一旦別シート指してから戻しても同じようにTrueを返す。

Sub hoge()
    Dim sh As Worksheet
    MsgBox Sheets(1) Is Sheets(1).Next.Previous
End Sub

つまりこれが固有オブジェクトであるということ。

ひとつのセルに対応する固有のオブジェクトが存在しないという意味が伝わっただろうか。




以上の内容はhttps://thom.hateblo.jp/entry/2017/04/16/021320より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14