エクセルVBAでProperty Letプロシージャを使ってプロパティ設定をする方法

みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。

「初心者でもわかるエクセルVBAのクラスモジュール」について連載でお送りしております。

前回の記事はこちらです。

エクセルVBAでプロパティを他のモジュールからアクセスできないようにする方法
「初心者でもわかるエクセルVBAのクラスモジュール」をテーマに連載をお伝えしています。今回はエクセルVBAでプロパティをプライベート変数で作成して他のモジュールからアクセスできないようにする方法です。

クラスにプライベート変数を宣言して、他のモジュールからアクセスできないプロパティを作成しました。

…って、他のモジュールからアクセスできないんじゃ、プロパティとして意味ないんじゃ…?

って思います?

私もそう思っていました。

ですが、大丈夫です。

直接アクセスできないのですが、間接的にはアクセスできるんです。

Propertyプロシージャを使ってね。

ということで、今回はエクセルVBAでProperty Letプロシージャを使ってプロパティ設定をする方法をお伝えします。

では、行ってみましょう!

スポンサーリンク

前回のおさらい

前回までのおさらいです。

まず、以下のようなエクセル表がありまして、この1行分のデータを表すクラスの作成を目指しています。

エクセルVBAでクラス化するエクセル表

クラスPersonの定義をするクラスモジュールには以下のようなコードが書かれています。

Private id_ As String
Public FirstName As String
Public Gender As String
Public Birthday As Date

Public Sub Greet()
    MsgBox Me.FirstName & "です、こんにちは!"
End Sub

Public Property Get IsMale() As Boolean
    IsMale = (Me.Gender = "male")
End Property

エクセル表の見出しに対応するプロパティをモジュール変数として定義。あと、便利そうなメソッドとプロパティを一つずつ追加しています。

確認用のSubプロシージャを記述している標準モジュールがこちらです。

Sub MySub()

Dim p As Person: Set p = New Person

Dim i As Long: i = 2
With Sheet1
    p.Id = .Cells(i, 1).Value
    p.FirstName = .Cells(i, 2).Value
    p.Gender = .Cells(i, 3).Value
    p.Birthday = .Cells(i, 4).Value
End With

Stop
'p.Greet

End Sub

ただ、残念現在は以下のようなコンパイルエラーが発生してしまうという状況なのです。

コンパイルエラー: データメンバーが見つかりません

なぜコンパイルエラーが出ているのか:これまでの経緯

事の発端はこうです。

まず、クラスPersonのIdプロパティはもともとはパブリック変数として定義していました。

ただ、パブリック変数で定義しちゃうと、Idプロパティを一度設定した後も、何度でも上書き、変更ができてしまう…それって、Idとしてドウなの?というわけです。

それを解決するために、Idプロパティをプライベート変数「id_」として定義をするように変更しました。

ですが、そうすると他のモジュールからアクセスできないわけで、インスタンスを生成したときに最初の正しいIdを設定するときにもアクセスできない…

こんなジレンマを抱えています。

それを解決するのが、今回の記事というわけです。

他のモジュールからプライベート変数にアクセスする方法

では、他のモジュールからプライベート変数にアクセスする方法について、ちょっと状況を整理しながら作戦を練りましょう。

まず、クラスモジュールPersonに定義したプライベート変数id_は、他のモジュールからはアクセスできません。これについてはお伝えした通りです。

プライベート変数は他のモジュールからアクセスできない

逆に考えてみましょう。

じゃあ、プライベート変数id_はどこからアクセスできるんでしたっけ??

と考えると、ほらクラスモジュールPerson内に記述したいずれかのプロシージャからであれば、変数id_はアクセスが可能なわけです。

プライベート変数は同じモジュール内からならアクセスできる

外側からがダメなら、内側から攻めればよいのですよ…!

で、そのPersonモジュール内に置くプロシージャですが、これを「パブリック」にしてあげれば、他のモジュールから呼び出し可能で、かつ引数を受け取れます。

Propertyプロシージャを迂回してプライベート変数にアクセスする

つまり、直接プライベート変数にアクセスするのではなく、何らかのプロシージャに値を渡して、そのプロシージャ内でプライベート変数を書き換えるんですね。

このように、プライベート変数の橋渡し役のプロシージャとして、Propertyプロシージャを使うことができるというわけです。

プライベート変数から値を取得するには、以前の記事で紹介したProperty Getプロシージャを使います。

そして、プライベート変数に値を設定するには、今回紹介するProperty Letプロシージャを使うのです。

このように、Propertyプロシージャによる迂回作戦でプロパティにアクセスするんですね。よく考えたものですね。

Property Letプロシージャとは

では、Property Letプロシージャとは何か、またその使い方について見ていきましょう。

Property Letプロシージャとは、プロパティを設定するときの手続きです。

つまり、プロパティを設定しようとしたときに、手続きを呼び出すことができます。

書き方はこうです。

Property Let プロシージャ名(仮引数 As 型)
 ’処理
End Property

Property Letプロシージャを定義すると、そのプロシージャ名がプロパティ名になります。

そして、例えば「Personオブジェクト.プロパティ = 値」というように、インスタンスに何らかの値を設定しようとしたときに、その値を引数としてProperty Letプロシージャが呼び出されることになります。

ちなみに、設定するものがオブジェクト参照の場合は、Property Setプロシージャを使います。

Property Letプロシージャでプロパティを設定する

実際に、Personクラスでの例を使ってProperty Letプロシージャを作ってみましょう。

以下のProperty LetプロシージャIdを、クラスモジュールPersonに追加します。

Public Property Let Id(ByVal newId As String)
    If id_ <> "" Then
        Debug.Print "Idは上書きすることはできません"
    Else
        id_ = newId
    End If
End Property

プロパティIdが設定される際に、Property LetプロシージャIdが呼び出され、かつプロパティの設定値をnewIdとして受け取ります。

If文がありますが、既にプライベート変数id_に何らかの空文字以外の文字列が格納されていれば、イメディエイトウィンドウにその旨通知するだけで、何もしません。

さもなくば、プライベート変数id_は初期状態ということになりますので、受け取った引数id_を格納します。

こうすることで、初回のIdの設定はできるが、それ以降の上書きはされないプロパティを作ることができるということになります。

Property Letプロシージャによるプロパティを確認する

F2 キーを押して、オブジェクトブラウザで様子を見てみましょう。

オブジェクトブラウザでProperty Letプロシージャによるプロパティを確認

Personクラスには、プライベート変数で宣言したプロパティ「id_」と、Property Letプロシージャで定義したプロパティ「Id」の2つが存在していますね。

前回、プライベート変数名を小文字+アンダースコアの形式にしたのは、これが理由です。

  • Personクラスモジュール内で実際にデータを持つのは変数id_
  • 他のモジュールからアクセスをするのはProperty LetプロシージャId

と使い分けをする必要があるからですね。

他のモジュールからアクセスさせないように、プライベート変数として宣言する場合は、小文字+アンダースコアという名前することで、上記の役割を明確化する慣習があるということです。

標準モジュールから呼び出して確認をする

では、実行をして確認してみましょう。

標準モジュールModule1のSubプロシージャを以下のように変更して実行してみます。

Sub MySub()

Dim p As Person: Set p = New Person

Dim i As Long: i = 2
With Sheet1
    p.Id = .Cells(i, 1).Value
    p.FirstName = .Cells(i, 2).Value
    p.Gender = .Cells(i, 3).Value
    p.Birthday = .Cells(i, 4).Value
End With

p.Id = "Hoge"
Stop
'p.Greet

End Sub

Stopステートメントで中断しているときの様子を確認すると、以下のようになります。

Property Letプロシージャを用いたプロパティの設定

ローカルウィンドウでは、プライベート変数id_が「a01」つまりエクセル表から最初に取得した値のままになっていることが確認できます。

つまり、初回の代入は成功していますね。

そして、イミディエイトウィンドウには「Idは上書きすることはできません」とあります。

これは、上書きしようとしたときに、再代入をせずに出力されたものです。

まとめ

以上、エクセルVBAでProperty Letプロシージャを使ってプロパティ設定をする方法をお伝えしました。

プロパティにアクセス制限をかけたい場合は、今回紹介したようにProperty Letプロシージャを使用します。

手続きを加えることができますので、多様な設定の仕方が実現できるというわけです。

さて、次回はプライベート変数によるプロパティを他モジュールから取得する方法です。

エクセルVBAでProperty Getプロシージャを使ってプライベート変数にアクセスする方法
「初心者でもわかるエクセルVBAのクラスモジュール」をテーマにシリーズ連載しています。今回はエクセルVBAでPropety Getプロシージャを使ってプライベート変数にアクセスする方法をお伝えします。

どうぞお楽しみに!

連載目次:初心者でもわかる!エクセルVBAでクラスを作ろう

名前は聞いたことあるけどよくわからない「クラスモジュール」。本シリーズでは、初心者でも少しずつ丁寧にその作り方と便利さについてお伝えしていきますよ!
  1. 【初心者でもできる】エクセルVBAで最も簡単なクラスを作る方法
  2. エクセルVBAでクラスに最も簡単なプロパティを追加する方法
  3. エクセルVBAで自作クラスをインスタンス化する方法
  4. エクセルVBAでクラスに最も簡単なメソッドを追加する方法
  5. エクセルVBAで表の1行分のデータを表すクラスを作成する方法
  6. エクセルVBAでProperty Getプロシージャを使って簡単なプロパティを作成する方法
  7. エクセルVBAでプロパティを他のモジュールからアクセスできないようにする方法
  8. エクセルVBAでProperty Letプロシージャを使ってプロパティ設定をする方法
  9. エクセルVBAでPropety Getプロシージャを使ってプライベート変数にアクセスする方法
  10. エクセルVBAでクラスのインスタンス生成時に初期データを格納するメソッドを作る方法
  11. エクセルVBAでインスタンスの集合をコレクション化する方法
  12. エクセルVBAでコレクション化したインスタンスを取り出す方法
  13. エクセルVBAでクラスモジュールを使って独自のコレクションを作る方法
  14. エクセルVBAでインスタンス生成時に自動で処理を実行するイベントプロシージャClass_Initialize
  15. エクセルVBAで自作コレクションのインスタンス生成時に初期データも投入する方法
  16. エクセルVBAで自作コレクションの要素を取得するプロパティの作り方
  17. エクセルVBAで自作のコレクションに要素を追加するメソッドを作成する
  18. エクセルVBAで自作コレクションの要素を削除するメソッドの作り方
  19. エクセルVBAでエクセル表のデータを反映するメソッドとクラスを使うメリット
タイトルとURLをコピーしました