ユーザー定義型の制限とクラスとの使い分け
VBAにはユーザー定義型(Type)があり、複数の要素(複数のデータ型)を含むデータ型を定義できます。
複数の値をひとまとめで扱う方法として配列がありますが、配列は同じ型の値しか扱うことができませんが、
ユーザー定義型の変数には、文字列型、数値型等々の複数のデータ型をひとまとめにして入れることができます。
また、
ユーザー定義型の機能は、クラスにインスタンス変数(Public変数やPublicプロパティ)を作ることで同じことができます。
ユーザー定義型
以降の説明で使うユーザー定義型は以下になります。
Public Type TypePerson
番号 As Long
名前 As String
住所 As String
End Type
標準モジュールのモジュールレベルに記述します。
クラスについて
以降の説明で使うクラスは以下になります。
Option Explicit
Public 番号 As Long
Public 名前 As String
Public 住所 As String
クラスのオブジェクト名:clsPerson
ユーザー定義型とクラスの速度比較
100万件の配列での比較をしています。
計測時間については、複数回実行の平均値ですが、
そもそも、PC環境によりますので、あくまで対比としての参考です。
Sub type_sample1()
Dim sTime As Double
sTime = Timer
Dim tPerson() As TypePerson
ReDim tPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
tPerson(i).番号 = i
tPerson(i).名前 = "名前" & i
tPerson(i).住所 = "住所" & i
Next
Debug.Print Timer - sTime
End Sub
Sub class_sample1()
Dim sTime As Double
sTime = Timer
Dim cPerson() As New clsPerson
ReDim cPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
cPerson(i).番号 = i
cPerson(i).名前 = "名前" & i
cPerson(i).住所 = "住所" & i
Next
Debug.Print Timer - sTime
End Sub
ユーザー定義型:type_sample1
0.3875秒
2.0453秒
クラスは、インスタンス作成の時間がかかるので仕方ありません。
とはいえ、100万回で2秒ですから、通常は処理時間として考慮するレベルのものではないと思います。
上記VBAは、Forループ内で
Set cPerson() = New clsPerson
このようにしても、処理時間は変わりません。
この記事を書くためにテストVBAを実行した範囲の事ですが、
クラスのVBAは実行後に何度かエクセルが反応なしになっています。
PC環境の問題もあると思いますが、VBAのメモリ解放に問題があるかもしれません。
Sub type_sample2()
Dim sTime As Double
sTime = Timer
Dim tPerson() As TypePerson
ReDim tPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
tPerson(i) = type_sub2(i)
Next
Debug.Print Timer - sTime
End Sub
Function type_sub2(i As Long) As TypePerson
type_sub2.番号 = i
type_sub2.名前 = "名前" & i
type_sub2.住所 = "住所" & i
End Function
Sub class_sample2()
Dim sTime As Double
sTime = Timer
Dim cPerson() As clsPerson
ReDim cPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
Set cPerson(i) = class_sub2(i)
Next
Debug.Print Timer - sTime
End Sub
Function class_sub2(i As Long) As clsPerson
Set class_sub2 = New clsPerson
class_sub2.番号 = i
class_sub2.名前 = "名前" & i
class_sub2.住所 = "住所" & i
End Function
ユーザー定義型:type_sample2
0.6734秒
2.1203秒
対して、クラスではほとんど時間の変化がありません。
ユーザー定義型は、データを値で渡していて(つまりデータをコピーしている)、
クラスはオブジェクトへの参照を渡している事に起因します。
クラスはオブジェクトとして、そのオブジェクトのアドレスを渡しているのでループ内で直接入れている場合とほとんど差が無いという事です。
Sub type_sample3()
Dim sTime As Double
sTime = Timer
Dim tPerson() As TypePerson
ReDim tPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
Call type_sub3(tPerson(i), i)
Next
Debug.Print Timer - sTime
End Sub
Sub type_sub3(ByRef arg As TypePerson, i As Long)
arg.番号 = i
arg.名前 = "名前" & i
arg.住所 = "住所" & i
End Sub
Sub class_sample3()
Dim sTime As Double
sTime = Timer
Dim cPerson() As clsPerson
ReDim cPerson(1 To 1000000)
Dim i As Long
For i = 1 To 1000000
Call class_sub3(cPerson(i), i)
Next
Debug.Print Timer - sTime
End Sub
Sub class_sub3(arg As clsPerson, i As Long)
Set arg = New clsPerson
arg.番号 = i
arg.名前 = "名前" & i
arg.住所 = "住所" & i
End Sub
ユーザー定義型:type_sample3
0.4250秒
2.0703秒
どちらも引数で参照渡ししているので、アドレスを渡す事以外は差が無いという事です。
type_sample2のような戻り値を使うのではなく、
type_sample3のようにByRefでの使い方をしたほうが良いでしょう。
この制限は、配列と同様になります。
ByRef指定にするか、指定を省略してください。
ユーザー定義型の制限
ユーザー定義型はVariant変数に入れることはできません
Sub type_sample4()
Dim v
Dim tPerson As TypePerson
v = tPerson
End Sub
これはコンパイルエラーになります。

同じユーザー定義型変数同士であれば入れることはできます。
クラスはVariant変数に入れられます
Sub type_sample6()
Dim dic
Set dic = CreateObject("Scripting.Dictionary")
Dim tPerson As TypePerson
dic.Add "key", tPerson
End Sub
クラスなら問題ありません。
このような場合はクラスを使用してください。
ユーザー定義型はCollectionに入れることはできません
Sub type_sample5()
Dim col As New Collection
Dim tPerson As TypePerson
col.Add tPerson
End Sub
これもコンパイルエラーになります。
クラスはCollectionに入れられます
Sub class_sample5()
Dim col As New Collection
Dim cPerson As clsPerson
col.Add cPerson
End Sub
クラスなら問題ありません。
このような場合はクラスを使用してください。
ユーザー定義型はDictionaryに入れることはできません
Sub type_sample6()
Dim dic
Set dic = CreateObject("Scripting.Dictionary")
Dim tPerson As TypePerson
dic.Add "key", tPerson
End Sub
これもコンパイルエラーになります。
クラスはDictionaryに入れられます
Sub class_sample6()
Dim dic
Set dic = CreateObject("Scripting.Dictionary")
Dim cPerson As New clsPerson
dic.Add "key", cPerson
End Sub
クラスなら問題ありません。
このような場合はクラスを使用してください。
ユーザー定義型の制限とクラスとの使い分け
ただし、あくまでオブジェクトを作成することと、データ型を定義することの違いは理解しておきましょう。
インスタンス作成したオブジェクト変数を他のオブジェクト変数に入れた場合、
実体のオブジェクトは同じもので、オブジェクトがコピーされるわけではありません。
つまり、オブジェクトへの入り口をコピーしたにすぎません。
対して、ユーザー定義型はあくまでデータです。
ユーザー定義型の変数を他の同じユーザー定義型の変数に入れた場合はデータがコピーされます。
ここを理解した上で、ユーザー定義型とクラスを使い分けることが最も重要です。
逆の見方をすれば、この違いを意識する必要がないのであれば、
ユーザー定義型の制限だけ意識していれば、都度どちらを使っても大差ないとも言えます。
同じテーマ「マクロVBA技術解説」の記事
VBAにおける配列やコレクションの起点について
VBAのマルチステートメント(複数のステートメントを同じ行に)
クリップボードに2次元配列を作成してシートに貼り付ける
ユーザー定義型の制限とクラスとの使い分け
シングルクォートの削除とコピー(PrefixCharacter)
空文字列の扱い方と処理速度について(""とvbNullString)
VBAにおける変数のメモリアドレスについて
Evaluateメソッド(文字列の数式を実行します)
Rangeオブジェクトの論理演算(差集合と排他的論理和)
VBAで写真の撮影日時や音楽動画の長さを取得する
VBAでWindowsMediaPlayerを使い動画再生する
新着記事NEW ・・・新着記事一覧を見る
第5章:AI×VBAでつまづかない!トラブルシューティングとAIとの付き合い方
|生成AI活用研究(2025-05-20)
第4章:【事例で学ぶ】AIとVBAでExcel作業を劇的に効率化する!
|生成AI活用研究(2025-05-20)
第3章:AIを「自分だけのVBA先生」にする!質問・相談の超実践テクニック|生成AI活用研究(2025-05-19)
第2章 VBAって怖くない!Excelを「言葉で動かす」(超入門)|生成AI活用研究(2025-05-18)
第1章:AIって一体何?あなたのExcel作業をどう変える?(AI超基本)|生成AI活用研究(2025-05-18)
AI時代のExcel革命:AI×VBAで“書かない自動化”超入門|生成AI活用研究(2025-05-17)
Geminiと100本ノック 23本目:シート構成の一致確認|生成AI活用研究(5月16日)
AIが問う出版の未来は淘汰か進化か:AIと書籍の共存の道とは|生成AI活用研究(2025-05-16)
Geminiと100本ノック 22本目:FizzBuzz発展問題|生成AI活用研究(5月15日)
すぐに使える!生成AI プロンプト作成 実践ガイド|生成AI活用研究(2025-05-15)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.繰り返し処理(For Next)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.ひらがな⇔カタカナの変換|エクセル基本操作
6.RangeとCellsの使い方|VBA入門
7.メッセージボックス(MsgBox関数)|VBA入門
8.セルのクリア(Clear,ClearContents)|VBA入門
9.FILTER関数(範囲をフィルター処理)|エクセル入門
10.条件分岐(Select Case)|VBA入門
- ホーム
- マクロVBA応用編
- マクロVBA技術解説
- ユーザー定義型の制限とクラスとの使い分け
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。