Historia pytania
Właściwości w Visual Basic pozwalają na enkapsulację logiki pobierania i ustawiania wartości. Wprowadzenie właściwości sprawia, że kod staje się bardziej czytelny i bezpieczny, eliminując potrzebę bezpośredniego dostępu do pól klasy i ułatwiając wdrażanie logiki walidacji lub obliczeń bezpośrednio w obiektach.
Problem
Nowicjusze często udostępniają pole publicznie lub używają właściwości automatycznych bez gettera/settera zawierających logikę, co prowadzi do naruszenia enkapsulacji lub niemożności realizacji wartości obliczanych. Innym problemem jest rekurencyjne wywołanie właściwości wewnątrz samej siebie, co prowadzi do StackOverflow.
Rozwiązanie
W Visual Basic ogłasza się prywatne pole, a właściwość zawiera bloki Get i Set z potrzebną logiką. Właściwości obliczane używają tylko Get, zwracając obliczoną wartość na podstawie prywatnych pól. Wewnątrz bloku set zawsze należy odwoływać się do prywatnego pola, aby uniknąć nieskończonej rekurencji.
Przykład kodu:
Private _price As Decimal Private _quantity As Integer Public Property Total As Decimal Get Return _price * _quantity ' właściwość obliczana 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
Kluczowe cechy:
Czy można w obrębie Set Price odwoływać się do właściwości Name, jeśli również jest zaimplementowana przez prywatne pole?
Tak, jeśli w bloku set właściwości Price odwołasz się do innej właściwości (np. Name), jest to dozwolone, ponieważ odwołania do różnych prywatnych pól nie wywołują rekurencji. Należy unikać odwoływania się do samego siebie: wywołanie Price wewnątrz Set Price spowoduje rekurencję.
Przykład kodu:
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
Co się stanie, jeśli w bloku Get właściwości wywołam tę właściwość ponownie?
To doprowadzi do nieskończonej rekurencji i StackOverflow. W bloku get zawsze używaj prywatnego pola, w przeciwnym razie właściwość będzie wywoływać samą siebie.
Public Property Amount As Decimal Get Return Amount ' doprowadzi do nieskończonej rekurencji End Get Set(value As Decimal) _amount = value End Set End Property
Czy można zadeklarować właściwość tylko do zapisu (WriteOnly) i jakie to niesie ryzyko?
Istnieją właściwości WriteOnly, ale ich użycie nie jest zalecane, ponieważ obiekt traci możliwość zwrócenia wartości, co pogarsza czytelność i przewidywalność. Jeśli jest potrzebna tylko do zapisu — lepiej przemyśleć architekturę.
Private _secret As String Public WriteOnly Property Secret As String Set(value As String) _secret = value ' Można zapisać, ale nie można uzyskać. End Set End Property
Programista postanowił uczynić pole Price publicznym i bezpośrednio z nim pracował. W rezultacie Price czasami stawał się ujemny przez błąd.
Zalety:
Wady:
Kolega zastąpił Price właściwością z prywatnym polem i walidacją w bloku set, co zapobiegło nieprawidłowym wartościom.
Zalety:
Wady: