問題の背景
Visual Basicのプロパティは、値の取得と設定のロジックをカプセル化することを可能にします。プロパティが導入されることで、コードはより読みやすく、安全になり、クラスフィールドへの直接アクセスの必要性が排除され、バリデーションや計算ロジックをオブジェクト内に直接組み込むことが容易になります。
問題
初心者はしばしばフィールドをパブリックにしたり、ロジックを含まないゲッター/セッターなしのオートプロパティを使用してしまい、これがカプセル化の違反や計算値の実装不可能につながります。もう一つの問題は、プロパティ内で自分自身を再帰的に呼び出すことで、StackOverflowを引き起こすことです。
解決策
Visual Basicでは、プライベートフィールドを宣言し、プロパティには必要なロジックを持つGetおよびSetブロックを含めます。計算プロパティはGetだけを使用し、プライベートフィールドに基づいて計算された値を返します。setブロック内では常にプライベートフィールドにアクセスし、無限再帰を避ける必要があります。
コード例:
Private _price As Decimal Private _quantity As Integer Public Property Total As Decimal Get Return _price * _quantity ' 計算プロパティ End Get End Property Public Property Price As Decimal Get Return _price End Get Set(value As Decimal) If value < 0 Then Throw New ArgumentException("Price must be positive") _price = value End Set End Property
主要な特徴:
Set Price内でNameプロパティにアクセスすることはできますか?それもプライベートフィールドで実装されていますか?
はい、setブロック内で他のプロパティ(例えば、Name)にアクセスすることは許可されています。異なるプライベートフィールドへのアクセスは再帰を引き起こさないためです。ただし、自分自身へのアクセスは避けるべきです:Set Price内でPriceを呼び出すと再帰が発生します。
コード例:
Public Property Name As String Get Return _name End Get Set(value As String) _name = value End Set End Property Public Property Price As Decimal Get Return _price End Get Set(value As Decimal) If Name Is Nothing Then _name = "default" _price = value End Set End Property
Getブロック内でこのプロパティを再度呼び出したらどうなりますか?
これは無限再帰を引き起こし、StackOverflowになります。getブロック内では常にプライベートフィールドを使用しなければなりません。さもなければ、プロパティは自分自身を呼び出すことになります。
Public Property Amount As Decimal Get Return Amount ' 無限再帰を引き起こします End Get Set(value As Decimal) _amount = value End Set End Property
書き込み専用プロパティ(WriteOnly)を宣言することは可能ですか、それはどのように危険ですか?
書き込み専用プロパティは存在しますが、使用することは推奨されていません。オブジェクトは値を返すことができなくなるため、読みやすさや予測可能性が損なわれます。それが書き込み専用である必要がある場合は、アーキテクチャを見直すべきです。
Private _secret As String Public WriteOnly Property Secret As String Set(value As String) _secret = value ' 設定は可能ですが、取得は不可能です。 End Set End Property
プログラマーはPriceフィールドをパブリックにして直接操作しました。その結果、Priceが時々負の値になるというバグが発生しました。
プラス面:
マイナス面:
同僚はPriceをプライベートフィールドとsetブロックのバリデーションを用いてプロパティに置き換え、無効な値を防ぎました。
プラス面:
マイナス面: