いつのまにかRangeがrangeやRANGEに?
ExcelでのVBAで間違いなく一番使われるクラスと言えば、Rangeクラスです。
こんな書き方をして使います。
1 2 3 4 5 |
Sub TestSub() Dim r As Range Set r = Range("A1") End Sub |
ところがあるとき急に、「あれ? つづりがへんじゃね?」と気が付くことがあります。
こんな感じ。
1 |
Dim r As range |
Rangeが小文字の「range」になっていたりすることが。それとは逆に大文字になることもあります。
1 |
Dim r As RANGE |
よく見てみると、その変数だけでなくそのブックのすべてのコードのRangeクラスの大文字小文字が壊れてしまっています。以下はすべて小文字になった例です。
1 2 3 4 5 6 7 8 9 |
Sub TestSub() Dim r As range Set r = range("A1") End Sub Sub TestSub2() Dim r As range End Sub |
この現象はRangeクラスに限らず、どのクラスでも発生します。FileSystemObjectクラスが小文字のfilesystemobject、Fileクラスがfile、RegExpクラスがregexpのようになることがあります。
なぜこんなことになるのでしょうか?
クラス名が壊れる原因は?
このようにクラス名が壊れる原因は、そのブックのどこかの変数定義や引数定義で、以下のようにクラス名と同じ名前で変数名に小文字で「range」と書いた場所があるためです。
以下のようなコードですね。変数名を小文字でrangeと書いてしまい、それに釣られてクラス名も小文字になってしまいます。
1 |
Dim range As range |
小文字ではなく大文字に壊れることもあります。
1 |
Dim RANGE As RANGE |
他には関数の引数定義の場合もあります。
1 |
Sub TestSub3(RANGE As RANGE) |
あとは、これをどうやって直すか、です。
そもそも、変数名にクラス名と同じ名前で大文字と小文字を変えたからといって、それに引きずられてクラス名の大文字小文字が変わってしまうVBAの仕様というかバグがダメなんですが、こういうのはVBAあるあるで、もうこれはどうしようもないので、以下の直し方で直すしかありません。
壊れたクラス名の直し方
壊れたクラス名を直すには2段階必要になります。
- クラス名を付けた変数定義で、変数名を正しいクラス名で書き直します。変数名を直すことでクラス名も一緒に直ります。
(変数定義が「Dim range As range」であれば「Dim Range」に書き直します。これで変数名が修正されたと同時にクラス名のrangeがRangeに直り、「Dim Range As Range」となります。) - 変数名にクラス名を付けたままだと変数名とクラス名を混同するため、それを避けるため、変数名を変更します。
(「Dim Range As Range」を「Dim r As Range」などに書き直します。それ以降のコードで「Range.Value」などで利用している箇所があればすべて変更後の変数名「r.Value」などに書き直します。)
この2段階の順序を踏まずに、1をすっとばして2のいきなり変数名をクラス名とは違う名前にしても、クラス名は壊れたままになります。また、変数名を直さずにクラス名を正しく書き直しても直らずに元の間違った記述に戻ってしまいます。
誤って付けた変数名を正しいクラス名で書き直して、それから、変数名をクラス名とは違う名前にしないと、正しく直りません。
クラス名が壊れる範囲
なお、クラス名が壊れる範囲ですが、ブックに含まれる標準モジュールやシートやクラスモジュールなどが対象になります。
そのため、例えばBook1.xlsmでRangeクラスが「range」と小文字になっていても、ブックとしては別である個人用マクロブック(Personal.xlsb)や別のブックでは正しく「Range」と表示されます。
このことから、クラス名が壊れた場合は、そのブックの中でそのクラス名を検索すればよいため、VBAの画面で検索画面を開き、対象欄で「カレント プロジェクト」のラジオボタンを付けて検索すればおかしくなった原因の変数定義か引数が見つかります。
変数名にクラス名と同じ名前を付けちゃダメ
そもそもの原因は、変数名にクラス名を付けようとしていることが原因です。
それで動作するので問題はないように感じますが、そのような勘違いを起こすようなコードは書くべきではありません。
本件の問題を起こすのはJava言語をメインに使っている方が多いのではないかと思っています。あくまでも推測ですが。
その理由ですが、Java言語の場合は「クラス名は大文字で始まり、変数名は小文字で始まる」との命名規則を設けていることが結構あります。結構あるというよりもほとんど業界標準に近い扱いです。そして、VBAで言う変数名にはクラス名を小文字で始まる形でそのまま使うことが多々あります。
これはVBAと異なりJava言語で変数を扱う場合はプリミティブ型(intとかcharとかの単純な型)かクラス型のどちらかを使うことが必須で、業務ロジックを書く場合はクラスが必須になり、またクラスも多数あることからクラス名と一緒にした方が分かりやすいという点があります。
Java言語は大文字と小文字が厳密に別で扱われるため、その命名規則で問題ありませんが、その慣習をVBAにも適用しようとすると、大文字と小文字が同一視されるVBAでは問題になります。
Java言語の感覚では「Range range = new Range()」と書いて、Rangeクラスのインスタンスrangeを作成、というよくある書き方をしますが、その考え方をVBAに適用すると、本件のようなクラス名の破壊が起こります。