初めてのVBA(オブジェクト型とは)


# 結論

先にこの記事の結論を述べておくと

    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 オブジェクト一覧表](https://kosapi.com/post-2864/)
[ExcelのVBAで利用したオブジェクト一覧](https://www.vba-ie.net/object/index.php)
上は一覧、下はその中でも比較的使われやすい(?)ものに絞られています。
実際ちょっとした確認程度なら下のサイトで十分かなと思います。


## 結局自分で確認するのが一番

今使いたいやつのデータ型を上記サイトの一覧からどれが当てはまるかなって探すのも少し手間です。
というわけで冒頭のコードが出てきます


    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を触るなら下の記事を読むのが本当におすすめです。
コメント欄も含めて準備から参考になるものが詰まっています。

https://qiita.com/opengl-8080/items/5bd8ae7fe95f5c31dfc3



以上、同じような悩みを抱えていた方の一助となれば幸いです。