どういうこと?
ExcelVBAのRangeオブジェクトはコレクションなんですかね? という素朴な疑問です。
資料によってRangeオブジェクトはコレクションと説明していたり、Rangeオブジェクトはコレクションではないと説明していたりします。
また、セミナーの講師がRangeオブジェクトにコレクションは存在しないと発言したという報告もよく見かけます。
いや、どっちやねんというのが本記事の趣旨になります。
ガッツリ解説しているページが見つからなかったので、調べていきます。
■NECによるMicrosoft Excel VBA 利用の手ほどき
「Rangeオブジェクトにはコレクションは存在しない」と説明しています。
■エクセルの神髄
「Rangeは、オブジェクトでもあり、コレクションでもあります」と説明しています。
■インストラクターのネタ帳
「『Rangesコレクションというものはありません』といった間違った記述を、Webなどで見かけることがありますけれど、Rangeはコレクションでもあるオブジェクトです」とかなり強く説明しています。
ちなみに、2024年1月時点では、ChatGPT3.5は「Rangeオブジェクトはコレクションである」と説明し、BingAI(Copilot?)は「Rangeオブジェクトのコレクションは存在しない」と唱えています。
Microsoft謹製のAIが自社で管理しているVBAの仕様について間違えるとは思いたくありませんが、ソースとして提示するのがQiitaの記事や個人ブログなので信憑性に欠けます。
Rangeオブジェクトとは
Microsoft LearnのVBAの言語リファレンスを確認します。
セル、行、列、連続した1つ以上のセルブロックを含むセルの選択、または3D範囲を表します。
うーん。今、知りたいのはそういうことではないんですよね。
しかし、このページを上から下まで眺めても、Rangeオブジェクトがコレクションなのか否かという記述は発見できません。
強いて言えば、RangeオブジェクトのCountプロパティの解説には、
コレクションに含まれるオブジェクトの数を表す長整数型 (Long) の値を返します。
とあり、Rangeオブジェクトがコレクションだと言っているように読めます。
ただし、これを以てRangeオブジェクトはコレクションなのだ!と声高に叫ぶには弱いように思います。
ちなみに、DictionaryオブジェクトのCountプロパティの解説には、
コレクションまたは Dictionary オブジェクト内の項目の数を含む Long (長整数) を返します。
という記述があり、DictionaryオブジェクトのCountプロパティの解説なのに、何故かコレクションに言及していたりします。Countプロパティ全般に関する解説なのだとすると、Countプロパティを持っているRangeオブジェクトはやはりコレクションと言えそうですが、同オブジェクトのItemプロパティではコレクションに関する記述はなく、どういう意図の解説なのか全く不明です。
頼むぞ、VBA言語リファレンス……!
コレクションの定義
Rangeオブジェクトの項目には記述がなかったので、今度はコレクションという大枠の項目から確認してみましょう。
Microsoft LearnのVBA言語リファレンスには以下のように記載されています。
コレクションは、通常は同じ種類 (そうでない場合もあります) の複数のオブジェクトを含んだオブジェクトです。 たとえば、Microsoft Excel では、Workbooks オブジェクトは開いているすべての Workbook オブジェクトを含みます。 Visual Basic では、Forms コレクションはアプリケーションのすべての Form オブジェクトを含みます。
コレクションのアイテムは、番号または名前を使用して識別することができます。 たとえば、次のプロシージャでは、開いている 1 番目の Workbook オブジェクトが識別されています。
意外と曖昧な定義です。VBAは継承をサポートしていないので、コレクションを継承しているかどうかといった明確な判断基準が存在しないのかもしれません。この辺りが論争を呼んでいる理由なのでしょう。
Rangeオブジェクトは同じ種類の複数のオブジェクト(Rangeオブジェクト)を含んだオブジェクトです。
RangeオブジェクトはRange("A1")のように名前を使用して識別することができます。
明言されている箇所が発見できなかったので、いまいちスッキリしませんが、
言語リファレンスの定義に従い、Rangeオブジェクトはコレクションだと言って差し支えはなさそうです。
余談① Rangesコレクションについて
Rangeオブジェクトについての記述で、「Rangesコレクションというものは存在しない」という記述をよく目や耳にします。
これを「なるほど! Rangeオブジェクトにはコレクションは存在しないんだ!」と誤解しているパターンも多そうです。
因みにRangesオブジェクトは存在しますし、RangesオブジェクトはRangeオブジェクトのコレクションらしいので、「Rangesコレクションというものは存在しない」という説明は誤りです。
ただ、WorksheetオブジェクトにおけるWorkSheetsコレクションに相当するものではないうえに、用途が限られるので、厄介です。
言語リファレンスにはどこで使用するのかについて記述がないのですが、下記サイトで触れられていました。
こちらによると、Rangesコレクションは、WorkbookConnection.Rangesプロシージャから取得できるとのことです。
個人で試した限りでは、パワークエリなどで接続を設定した場合に、その接続を利用したテーブルなどが置かれた範囲を取得しているように見えます。
まとめると、
「Rangesコレクション自体は存在するし、Rangeオブジェクトのコレクションだが、WorksheetオブジェクトにおけるWorkSheetsコレクションに相当するようなRangesコレクションは存在しない」
ということです。
余談② じゃあCellsは?
CellsのことをRangeオブジェクトのコレクションだと解説しているサイトも一部で存在します。
Worksheets("Sheet1").Cells.Select
なるほど、確かに上記のように記述すると全セルが選択されるので、Worksheetオブジェクトに対するWorkSheetsコレクションのように見えなくもないですね。
ただし、Cellsオブジェクトなるものは存在しません。言語リファレンスに存在しないので。
CellsというのはWorksheetオブジェクトやRangeオブジェクトのプロパティであり、返ってきているのもRangeオブジェクトです。
結論
RangeオブジェクトはRangeオブジェクトのコレクションである。
Rangesコレクション自体は存在するし、Rangeオブジェクトのコレクションだが、WorksheetオブジェクトにおけるWorkSheetsコレクションに相当するようなRangesコレクションは存在しない。