結論
先にこの記事の結論を述べておくと
Debug.Print TypeName(something)
を逐次使いましょう、です。
オブジェクト型ってなんだよ
VBAを初めて触った時に自分が一番詰まった部分。
Integer
、String
、Boolean
など基本的な型以外のほとんどがこれに当たります。
Workbook
、Worksheet
、Range
みたいなやつのデータ型の総称が"オブジェクト型"。
Excelのシートで
- 1つのセルに入るもの = 数値、文字、True/Falseなど……が "NOT オブジェクト型"
- 1つのセルに入らない = ブック、シート、範囲、配列などが "オブジェクト型"
と考えるのが分かりやすいかもしれません。
NOT オブジェクト型というのは正式な呼び方ではありませんが、便宜上こう呼ぶことにします。
だいたいのやつはオブジェクト型の一種ってことですね。
なにがそんなに詰まらせたのか
これはエラー文のガバさにあります。
「オブジェクトを利用できません」
「オブジェクトが必要です」
「オブジェクトの使い方が不正です」
「オブジェクトがありません」
特に初学者だとこの手のエラー文が無限に出て来る。で、どこがエラーなのか分からない。
型宣言をちゃんとしたらいいのかな?という漠然とした解決のイメージはありましたが、
オブジェクト型とは何なのか呑み込めず、
また、Dim hoge As Object
のようにしているコードもあり、
Workbook
などとは別の分類のデータ型なのか、のような勘違いをしたことで余計に混乱を生んでいました。
原因
- どこかからコピペしたコードが変数宣言を
Variant
にしている - 宣言した変数にオブジェクト型のものを入れたいのに代入時に
set
を書いていない
のどちらかが多いです。set
については後述。
VBA自体が結構古くから存在することもあり、コードの作成者が作成当時に正確性への意識を持っていない限り
全部突っ込める便利なデータ型としてVariant
が使われていることが多いです。
結果、自分がそういったコードをいくつか拝借して組み合わせ、思うように動かそうとすると
どこかで噛み合わず上記のようなエラーが頻発する、というワケです。
解決法
一旦Variant
型の変数に入れた後、Variant
のまま渡そうとするからエラーの原因を特定しにくくなっています。
正確なデータ型をはっきり記述すれば型が原因のエラーは起こりにくくなり、
またエラー発生時も、データ型をキーワードに入れてググることでその原因を特定しやすくなります。
副産物として、データ型を含めてググるとよりスマートなコードが出やすいとかもあります。
値を渡す必要がなく、そのSub/Functionプロシージャ内で完結していればVariant
を使うのも一つの手ですが、
マクロを拡張してできることを増やしたい、応用したいとなった時のためにも
当たり前のことですが、変数宣言時は極力正確なデータ型を記述するのが好ましいです。
そもそもこれを分かってない人はqiitaなんてサイトほとんど見ないと思うんですけど、
なんでも入れられる便利なデータ型あるって聞くとめんどくさくなったら使いたくなっちゃうんですよね。私もそうでした。
苦悩は続く
で、変数宣言のデータ型一覧を探そうとしました。
「vba 変数宣言 型」ポチー
出て来る記事が全部基本の型に関してしか書いてないんですよね。オブジェクトについても書けよ。
挙句「型は覚えなくていい」「わからなかったらVariant
でいいよ」って記事が結構上に来ます。
こういうやつのせいでみんな混乱してるんだよ
ちなみにその記事があるサイトの個別のコードは結構お世話になりました。
マイクロソフトが一覧書いてないかな~ってググった結果
オートメーションを通してアプリケーションによって公開されるオブジェクトの型。たとえば、Application、File、Range、Sheet などがあります。 使用できるオブジェクトの詳細な一覧については、オブジェクト ブラウザー を使用するか、アプリケーションのドキュメントを参照してください。
オブジェクトブラウザーはVBエディタから確認できるヤツです。
ただの一覧でしかなく何のためのデータ型なのかも非常に分かりづらい。
ブラウザ上で一覧で見れて何のための型かも分かるページがあればな~~
と、ここで下記の2サイトを見つけました。
Excel VBA オブジェクト一覧表
ExcelのVBAで利用したオブジェクト一覧
上は一覧、下はその中でも比較的使われやすい(?)ものに絞られています。
実際ちょっとした確認程度なら下のサイトで十分かなと思います。
結局自分で確認するのが一番
今使いたいやつのデータ型を上記サイトの一覧からどれが当てはまるかなって探すのも少し手間です。
というわけで冒頭のコードが出てきます
Dim something As Variant
something = 調べたいやつ
Debug.Print TypeName(something)
一旦Variant
として変数にデータを入れた後、じゃあこれのデータ型って何?と確認したらちゃんと答えてくれます。
somethingの部分に型が分からない変数の名前を入れて確認しましょう。
できるならエラー文に反映させろよ
使用例
いくつか例を出しておきます
Sub test()
Dim wb As Variant
Set wb = ActiveWorkbook
Debug.Print TypeName(wb)
Dim sh As Variant
Set sh = ActiveSheet
Debug.Print TypeName(sh)
Dim shRange As Variant
set shRange = sh.Range("A1:C3")
Debug.Print TypeName(shRange)
Dim x As Variant
x = 12345
Debug.Print TypeName(x)
Dim y As Variant
y = 123456789
Debug.Print TypeName(y)
Dim z As Variant
z = "あいうえお"
Debug.Print TypeName(z)
End Sub
上から順にそれぞれの型が
Workbook
Worksheet
Range
Integer
Long
String
とイミディエイトウィンドウに表示されるはずです。
調べられたら、Variant
としていた型を
Dim wb As Workbook
などのように正確なデータ型へ修正していきましょう。
確認したいのにエラー出たんだけど?
変数に代入する際のset
が原因かもしれません。
Integer
などのNOT オブジェクト型は必要ないですが、
Workbook
、Worksheet
、Range
などのオブジェクト型はset
が必要です。
「使用例」のサンプルコードを見返してみてください。ちゃんとset
が書いてありますね?
こういう注意点、当然ですがパクりたいサンプルコードには一切書いてないのでずっと頭にハテナが浮かんでいました。
最後に
オブジェクト型かどうかの区別が自分の中で一番もやもやしていた部分だったので、
冒頭の「セルに入るかどうか~」という分類は我ながら分かりやすいなと思っています。
VBAを触るなら下の記事を読むのが本当におすすめです。
コメント欄も含めて準備から参考になるものが詰まっています。
以上、同じような悩みを抱えていた方の一助となれば幸いです。