カスタムDictionaryクラスを作ろう(6)

カスタムDictionaryクラスを作ろう(6)

 

akashi-keirin.hatenablog.com

前回の続きです。

過去記事

ここまでで、すでにだいぶ長くなってきているので、現時点のソースコードを載せておきましょう。

現時点の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」側の実装ですね。

akashi-keirin.hatenablog.com