プロパティとは何か?

プロパティは、クラスモジュールで定義しているPrivate 変数を外部から取得・設定する関数のことを指します。クラスの場合は関数と言わずに「インターフェース」という言い方をしますが、ここではイメージしやすいように「関数」と書いています。

クラス内部のPrivate 変数はPrivate(非公開)のため外部から直接参照できません。しかし外部から変数値を参照したり変更したりする必要が出てきます。そのような場合にプロパティを用意します。

VBAのクラスでは以下の3種類のプロパティがあります。

構文 役割 引数
Property Get プロパティ名() 値の取得(読み取り) 引数はありません。
Property Let プロパティ名(ByVal value As 値型) 値の設定(書き込み、値型用) クラスのPrivate変数に設定する値を指定します。
Property Set プロパティ名(ByVal value As オブジェクト型) 値の設定(書き込み、オブジェクト用) クラスのPrivate変数に設定するオブジェクト型の値を指定します。

Letの引数の値型とは、Integer、Long、Double、String、Boolean などの値型データを対象としています。

Setの引数のオブジェクト型とは、Object、Range、Dictionary、自作クラス などのオブジェクト型データを対象としています。

オブジェクト型についての詳細は「VBAのオブジェクトとは?分かる言葉で説明します」をご参照ください。

プロパティの引数はByRefではなくByValを使うべき理由

プロパティのLet と Setの引数で、プロパティの Let および Set の引数には、通常 ByVal(値渡し)を使うべきとされています。

その理由は、ByRefを使うと、呼び出し元の変数が意図せず書き換えられる可能性があるためです。これは、クラス内部の実装を変更しただけで外部に影響を及ぼすことになり、バグの原因になります。

通常のプロパティは「クラス内部のPrivate変数に値をセットすること」が目的であり、外部に影響を与えないようにするためにも ByVal を使うのが安全です。

一応以下のように「ByRef」で渡せますが、こういうコードはやめておきましょう。

この例では、渡された値そのものが関数内で書き換わっていることが確認できます。

プロパティ Get / Let / Setの違いと使い分け(値型・オブジェクト型)

数値や文字列(=値型)のプロパティなら Let を使い、オブジェクト(Dictionary や Range など)なら Set を使います。

以下はGet、Let、Setでのサンプルです。

なお、コード内でDictionaryを使っていますが、Dictionaryを使う場合は事前にVBA画面のツールメニュー→参照設定を選び、参照設定ダイアログで「Microsoft Scripting Runtime」にチェックを付けます。

Dictionaryの詳細については「VBAのDictionaryの使い方(全メソッドとプロパティ網羅)」をご参照ください。

この例では、mName という Private(非公開)変数を定義し、Name プロパティを通して値の取得・設定を行っています。 Private 変数は外部から直接アクセスできませんが、プロパティを介することで安全にアクセスできるようになります。

ここでは単純に変数の値を返しているだけですが、今後プロパティ内部で値の加工処理やエラーチェックなどを追加する場合、プロパティ経由のほうが柔軟性が高くなります。

オブジェクト型の場合も値型と考え方は同じで、LetとSetが違うぐらいですが、オブジェクト型のプロパティでは、「Set」を使って「オブジェクトの参照」を正しく代入する必要があります。「Set」を使わずに代入すると、エラーになるので注意してください。

読み取り専用プロパティの実装(Get のみ定義して変更不可に)

一度設定したら外部から変更させたくない情報は、Get のみを実装して「読み取り専用」にします。たとえば、クラスを識別する ID や、クラスが作成された日時などが該当します。

以下は「作成日時」を読み取り専用プロパティとして定義する例です。

このコードでは値を参照するためのGetプロパティは用意していますが、値を書き換えるLetプロパティは「書き換えてほしくないのに書き換わってしまう」という問題を起こすため用意していません。

このコードでは、mCreated 変数にクラス生成時の日時を クラス開始時に呼び出されるClass_Initialize イベントで格納し、それをGetプロパティ経由で読み取れるようにしています。

書き換えを防ぐために、Let プロパティはあえて定義していません。これにより、外部から 作成日時のCreatedAt 変数の値を変更できない安全な設計になります。

書き込み専用プロパティの実装(Let のみ定義してセキュリティ向上)

ユーザーに「設定だけさせて、取得はさせたくない」ケースでは Let プロパティだけを定義することができます。典型的な例として「パスワード」などが挙げられます。

このように、パスワードのような機密性の高い情報は、外部から読み取られないように Get プロパティをあえて用意しません。書き込み専用にすることで、情報漏洩のリスクを減らすことができます。

プロパティで値をチェックする方法(例:年齢に負の数を禁止)

プロパティは単なる変数の代入/取得ではなく、関数として処理を記述できます。

そのため、Let や Set プロパティで値を受け取る際に、値の妥当性をチェックする処理を加えるのが一般的です。たとえば、クラスの内部状態を破損させないために、異常な値(負の年齢など)を弾くようにします。

このように、プロパティを経由することで、変数に直接代入するよりも柔軟なチェックや制御が可能になります。

オブジェクト型のプロパティ(Setを使う例)

Dictionary や Range など、オブジェクトを保持する場合は Property Set を使います。

Setプロパティの内部処理で引数オブジェクトをクラス内部のPrivate変数に代入を行う場合も、Setを付ける必要があります。この「Set」は「Property Set」とは関係なく、オブジェクトの代入を行う際に付ける「Set」ステートメントです。値型と異なり、Set ステートメントを忘れると、「型の不一致」などのエラーになります。

オブジェクト型を扱うときは、取得(Get)にも Set ステートメントを使う必要がある点にも注意してください。また、不要になったオブジェクトを解放したい場合は以下のように Nothing を代入します。

実用例:社員クラスのプロパティ活用パターン

Get、Let、Setの各プロパティをまとめたクラスモジュールのサンプルです。

コード内でDictionaryを使っていますが、Dictionaryを使う場合は事前にVBA画面のツールメニュー→参照設定を選び、参照設定ダイアログで「Microsoft Scripting Runtime」にチェックを付けます。

上の社員クラスを外部から使う場合のサンプルコードが以下になります。標準モジュールに記述して実行すると動作します。

まとめ:プロパティの設計はクラスの質を左右する

プロパティの設計次第で、クラスは「使いやすく、安全で、信頼できるもの」になります。

以下がプロパティを作る際の指針になります。

1. Get / Let / Set の役割を正しく理解する

  • Get: 外部に値を渡す(参照させる)
  • Let: 外部から値を受け取って代入
  • Set: 外部からオブジェクトを受け取って代入(Object 型の場合のみ)

値型(Long, Stringなど)とオブジェクト型(Range, Dictionaryなど)で使うキーワードが異なる点をしっかり意識することが重要です。ミスすると「型の不一致」エラーになります。

2. 外部から見えるべき情報と、隠すべき情報を明確に分ける

  • すべての情報をプロパティで開放するのではなく、「必要な情報だけ」外に公開するのがクラス設計の基本です。
  • クラスの内部データを不用意に操作させないことで、予期せぬバグやデータ破壊を防げます。
  • 読み取り専用にしたい場合は Get のみ提供して Let や Set を作らない、などの工夫も大切です。

3. データの整合性はプロパティ内で守る

  • 不正な値の代入をプロパティ内部でチェックすることで、クラスの状態を常に正しく保つことができます。
  • 前セクションのように「負の値はエラーにする」「文字列をTrimする」「オブジェクトの初期化・解放を制御する」などは、まさにこれを実現するためのテクニックです。
  • プロパティを通すことで「検証ロジックの集中管理」ができ、クラス利用者が直接ミスを起こす余地を減らせます。