カスタムDictionaryクラスを作ろう(6)
前回の続きです。
過去記事
ここまでで、すでにだいぶ長くなってきているので、現時点のソースコードを載せておきましょう。
現時点のDictionaryモジュール
ソースコードを
Option Explicit
Public Enum CompareMethod
BinaryCompare = 0
TextCompare = 1
DatabaseCompare = 2
End Enum
Private m_Dictionary As Object
Private Sub Class_Initialize()
Set m_Dictionary = CreateObject("Scripting.Dictionary")
End Sub
Public Property Get CompareMode() As CompareMethod
CompareMode = m_Dictionary.CompareMode
End Property
Public Property Let CompareMode(ByVal CompareMode As CompareMethod)
Const ERR_SOURCE As String = "`CompareMode` property(Let)"
' 本家Dictionaryは、要素追加後にCompareModeを設定しようとするとエラーになる
' -> ちょっと親切なエラーを吐く
If m_Dictionary.Count > 0 Then
Call RaiseError( _
a_Source:=ERR_SOURCE, _
a_Description:="要素追加後にCompareModeの変更はできない。")
End If
m_Dictionary.CompareMode = CompareMode
End Property
Public Property Get Count() As Long
Count = m_Dictionary.Count
End Property
Public Property Get Item(ByVal Key As Variant) As Variant
If IsObject(m_Dictionary.Item(Key:=Key)) Then
Set Item = m_Dictionary.Item(Key:=Key)
Else
Item = m_Dictionary.Item(Key:=Key)
End If
End Property
Public Sub Add( _
ByVal Key As Variant, _
ByVal Item As Variant)
Const ERR_SOURCE As String = "Add() method(Sub)"
' 既存のキーにアイテムを設定しようとした
If m_Dictionary.Exists(Key) Then
Call RaiseError( _
a_Source:=ERR_SOURCE, _
a_Description:="既存のキーにはアイテムを設定できない。")
End If
Call m_Dictionary.Add( _
Key:=Key, _
Item:=Item)
End Sub
Public Function Exists(ByVal Key As Variant) As Boolean
Exists = m_Dictionary.Exists(Key)
End Function
Private Sub RaiseError( _
ByVal a_Source As String, _
ByVal a_Description As String)
' エラーオブジェクトに渡すパラメータを用意
Dim errNum As Long, errDesc As String, errSrc As String
errNum = vbObjectError + 1
errSrc = "Dictionary class: " & a_Source
errDesc = "( ´,_ゝ`) < プークスクスw " & a_Description & "(クソが。)"
' 例外スロー
Call Err.Raise( _
Number:=errNum, _
Source:=errSrc, _
Description:=errDesc)
End Sub
Itemプロパティの実装(つづき)
今回は、前回作成したItemプロパティをデフォルトプロパティにします。

それにしても、オブジェクト ブラウザーで〝既定のメンバー〟であることを示す

このアイコン、何なのでしょう……?
VBA歴10年を超える剛の者である私にも、何を図案化したものなのかサッパリわかりません。
では、気を取り直してItemプロパティをデフォルトプロパティにしてみましょう。
.clsファイルをエクスポートする
まず、クラス モジュールDictionaryをエクスポートします。

プロジェクト エクスプローラー内でDictionaryを右クリックすると、コンテキストメニューが展開するので、「エクスポート」をクリックしましょう。
ファイル保存ダイアログが出るので、テキトーな場所に保存します。
ファイル拡張子.clsであるファイルとして保存されることになります。
ちなみに、このときにファイル名をAho.clsみたいに全然違う名前にしても、インポート(後述)したらちゃんとDictionaryクラスになります。
まあ、そんなことをするメリットはまずないですが。
昔はバージョンを管理するのにDictionary20191016.clsみたいにしていましたが、Gitを覚えた今、そんなこともしなくなりました。
テキストエディタで.clsファイルを開く
次に、テキトーなテキストエディタで先ほど保存したDictionary.clsファイルを開きます。

画像はVisual Studio Codeで開いたところです。

Visual Basic Editorには表示されない記述もありますね。
このあたりは、モジュールファイルのメタデータを記録した領域のようで、正直よくわからない部分です。
一般ユーザがいじる可能性があるとしたら、
Attribute VB_PredeclaredId = False
ここでしょうかね。
こいつをTrueにしてやると、変数にインスタンスを格納することなく、<クラス名>.<メンバ>の形でプロパティ・メソッドを利用することができるようになります。
状態を持たない、ないしは一度設定したら状態を変化させることがないようなオブジェクトなら、ここをTrueにしておくと、手軽に機能が利用できるので便利です。
私は、Windows API関数の宣言を大量に封印したクラスモジュールを作って(文字列のハッシュ値を算出するメソッドなんかを実装してある。)、便利に使い回しています。
テキストエディタで.clsファイルを編集する
ここで、前回実装したItemプロパティの記述を次のようにします。
リスト1
Public Property Get Item(ByVal Key As Variant) As Variant
Attribute Item.VB_UserMemId = 0
If IsObject(m_Dictionary.Item(Key:=Key)) Then
Set Item = m_Dictionary.Item(Key:=Key)
Else
Item = m_Dictionary.Item(Key:=Key)
End If
End Property
2行目のところに、
Attribute Item.VB_UserMemId = 0
これを追記しました。

エディタの画面はこんな感じになります。
ItemメンバのVB_UserMemIdという属性に0をセットした、ぐらいの意味でしょうか。
UserMemIdというのは、「User Member ID」の略でしょうかね?
〝ユーザが設定するメンバID〟を「0」(=先頭の値)に設定することによって〝デフォルトのメンバ〟ということを表しているのでしょう。(たぶん。)
保存をしたら、テキストエディタでの作業は終了です。
.clsファイルをプロジェクトにインポートしなおす
改造した.clsファイルをプロジェクトにインポートするには、プロジェクト エクスプローラーで右クリック→「ファイルのインポート」で良いのですが、

慌ててインポートすると、

こういうまぬけな事態を招きます。
同じ名前のモジュールをインポートしたときに〝上書き〟されるわけではないので注意。

このように、元あったDictionaryを「解放」(ポア)してからインポートし直しましょう。

VBEで見る限り、何にも変わってはいませんが、

オブジェクト ブラウザーで見ると、アイコンがよくわからないあのアイコンに変わっています。
おわりに
長くなったので続きは次回。
いよいよItemプロパティの「Write」側の実装ですね。