ただの感想というか…そういうネタです。
仕事柄、不本意ながらVBAを触る機会*1があります。
VBA…自分でメンテナンスできないなら最初から使うな、とは言いたいところですが、来てしまうので対応しています。
まあ…所詮はOfficeのおまけなので、機能は少ないし、今後発展する可能性も無いです。
C#が得意な筆者から見て、ExcelVBAの辛いところを語ってみます。
コンストラクタが無い
無いんです!
Dim item As MenuItem Set item = New MenuItem
と書きますが、
var item = new MenuItem(name);
みたいに、コンストラクタで引数を渡す方法が提供されていません。
※初期化と終了処理はあります。クラスに以下の処理を記述します。
インタンス生成後、はじめて参照された時点で、自動的に呼ばれます。
どのクラスであっても、同じ記述で良いです。
Private Sub Class_Initialize() fName = "My Name" End Sub
For Each
int total = 0; foreach(var item in items) { total += item.Point; }
みたいな、コレクションを順次処理する構文は、VBAにもあります。
が…
Dim items() As MenuItem 'ループ変数定義 Dim item As MenuItem 'ループ本体 For Each item in items Debug.Print item.Point Next item
上の処理はコンパイルエラーが発生します。
なぜか、For Eachで配列をループさせる場合は、Variantで変数を受ける
というルールがあります。
配列なら型ぐらいわかるだろ!という気はしますが、ダメらしいです。
戻り値が分かりづらい
前提として言いますが、VBAは継承という概念がありません*2。
よって、型がわかれば、その通りの動きをします。
しかし、よく使うRange
オブジェクトはかなり変な動きで…
対象として四角範囲、列、行を指定した場合で、それぞれ呼び出せないメソッドが変わったり、返してくる値が異なります。
Dim useRange As Range Set useRange = Sheet.Range("~~")
という形で、Rangeを取得します。
例えば、Range.Count
では、以下の値が返ってきます。
指定値 | 返却値 |
---|---|
四角指定 | セル数 |
列指定 | 指定範囲の列数 |
行指定 | 指定範囲の行数 |
取得方法によってメソッドの意味が変わるなんて、止めていただきたいです。
何が困るかというと、引数でRange
を受け取る際、それがどうやって生成されたか、気にしなければならない点です。
変数設定
上で、さらっと書きましたが、VBAの変数設定は、
- 基本型
Dim val As Integer val = 100
- クラス型
Dim useRange As Range Set useRange = Sheet.Range("~~")
のように、Set
を先頭に付与しなければなりません。
とても面倒です。
C#では、当然付ける必要が無く、付け忘れが多発します。
しかも、コンパイルエラーにならず、動かすまでエラーを吐かないのが、非常にいやらしいです。
コレクション
標準機能に絞ると、コレクションは「配列」と「コレクション(Collection)クラス」が該当します。
当然、ジェネリクスなどという、便利な代物はありません。
配列は、上で述べたように、ループ中でVariantで受ける制約が面倒で扱いづらい等、問題があります。
これの何が困るかというと…
Collectionをメソッド間で引き継げないという点です。
Collectionの中に何が入っているかわからない(なんでも入る)ため、中身を当てにした実装になってしまいます。
「引数でCollectionを受け取る」や、「クラスのメンバーとしてCollectionを公開する」というのが、非常にやりづらいです。
例外
C#でいう、try - catch
などという、おしゃれなものはありません。
エラーメッセージ
これはね…擁護できません。意味不明すぎて泣けます。
不満はあるのだけれども
オブジェクト指向でやろうとすると、いろいろと足りない部分は多いですが、そういうソースが書けないわけでもありません。
Range
が扱いづらいのならば、使うクラスは限定して、独自定義したクラスのインスタンスを受け渡せばよいです。
Excelのシートにアクセスするクラスを、Viewとして切り出してしまう等です。
Collection
が公開に向かないなら、目的特化した、最低限の操作を提供したクラスを自分で用意し、コレクションを受け渡さなくとも処理できるようにするとか。
継承は使えないけど、インターフェイスは使えるので、依存性の注入*3で多態を実現するとか。
オブジェクト指向として、綺麗なソースを書こうとすると、工夫のし甲斐はあります。
おわりに
上で、VBAを擁護しましたが、結局は修行みたいなものです。
ガスコンロがあるのに、わざわざ火を熾している、という感じです。
今後、何か新規で作る場合、VBAを使うのは避けたほうが良いです。
使うとしても、自分の手元に留めましょう。
ではでは。