|
|
 |
|
|
|
|
Visual Basic 2008 9.0 .NET Examples and Ebook
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Getter ( Get ) and Setter ( Set )
| Some object orientated programming languages have Property-constructions. These are a replacement for get-functions and set-procedures. |
| Namespace Example1
Class Person
Private m_Name As String
Public Property Name() As String
Get
Name = m_Name
End Get
Set(ByVal value As String)
m_Name = value
End Set
End Property
End Class
Module Client
Sub Main()
Dim person1 As Person = New Person
person1.Name = "John"
Console.WriteLine(person1.Name)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| The getter (1) of a property is executed when the property is read(4). The setter (2) is executed when the property is assigned a value (3). The value ( here String-literal "John" ) is assigned to the argumentvariable value of the setter.
As you can see the implementation of the getter and setter is identical to the implementations of the get-function and set-procedure of previous topic. The client has to be changed. The client can address the property the same way it would address a public field. Assigning a value to this property happens the same way a value would be assigned to a String variable. When reading out this property (4) a String expression is formed, just like a call to the corresponding get-function of previous topic. A String expression is returned in the implementation of the getter of this property.
By default the identifier of the argument variable of the setter is value, this can be changed, although there usually is no reason to change this identifier. The role of this argument is always the "value" to set.
The type referred to in the type specifier of signature of the property and in the type specifier of the argument declaration of the signature of the setter of this property, always have to be the same. In the above example both are As String.
A public field would result in a identical manner of use for the client. |
| Namespace Example2
Class Book
Public Title As String
End Class
Module Client
Sub Main()
Dim book1 As Book = New Book
book1.Title = "Some Title"
Console.Write(book1.Title)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| The advantage of working with Property-constructions ( or corresponding get-functions and set-procedures ) is that validation can happen. The assigned value can be manipulated before being stored by the setter ( or set-procedure ), and manipulated before being returned by the getter ( or get-function ). When addressing a public field no code/implementation can be executed.
Field are rarely made public. These are usually only necessary for the holding states. Holding as state is an implementation matter. And implementation matters are usually encapsulated.
Up till version 2005 there are few differences between Property constructions on the one hand and set-procedures and get-functions on the other hand. Properties in contrary to methods can be made default. Methods in contrary to properties can be pointed to with a delegate. Both default properties and delegates are rather rarely used in applications, so the choice between a Property construction and on the other hand a get-function and/or set-procedures was mainly a matter of person preference. Since Visual Basic 2008 the use of properties gives us some new advantages, one of them is the With construct in the object initializer. Some coding guidelines suggest to use a Property when the implementation consists of accessing a field. Setprocedures and getfunctions are suggested if a more complex implementation is needed.
Usually the identifier for a Property is a noun, for instance Name. In contrary to identifiers of methods, which are usually a verb or a combination of a verb and a noun, for instance SetName and GetName. |
Up
Access Modifiers for Getters and Setters
| It's possible to restrict the access modifier of the getter or the setter of a 'Property'.
For instance the setter can be scoped Private when the Property itself is Public. In that case only the getter is publicly available, the setter is encapsulated.
Following examples illustrates a Counter class with a Public Value property with a Private setter. |
| Namespace Example3
Class Counter
Private m_Value As Integer
Public Property Value() As Integer
Get
Value = m_Value
End Get
Private Set(ByVal value As Integer)
m_Value = value
End Set
End Property
Public Sub Raise()
Value = Value + 1
End Sub
End Class
End Namespace Download Broncode |
| Only within the class Counter Value can be set.
The following client can only read out the Value property. Setting this property is not allowed outside the class (3). |
| Namespace Example3
Module Client
Sub Main()
Dim counter1 As Counter = New Counter
Console.WriteLine(counter1.Value)
counter1.Raise()
Console.WriteLine(counter1.Value)
counter1.Raise()
Console.WriteLine(counter1.Value)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Abstraction wise this makes the property Value readonly for the clients.
Encapsulating the getter and allowing public access to the setter is rarely done, after all it wouldn't make much sense. |
Up
ReadOnly Property
| Derived properties of a concept usually are only queryable and not settable. Base ( state ) properties on the other hand usually can be set and queried.
A Product can have base ( state ) properties like Price and TaxPercentage and a derived property PriceIncludingTax.
The properties Price and TaxPercentage have a getter and setter. The Property-construction for PriceIncludingTax can be made ReadOnly.
A ReadOnly Property only has a getter. |
| Namespace Example4
Class Product
Private m_Price As Decimal
Public Property Price() As Decimal
Get
Price = m_Price
End Get
Set(ByVal value As Decimal)
m_Price = value
End Set
End Property
Private m_TaxPercentage As Decimal
Public Property TaxPercentage() As Decimal
Get
TaxPercentage = m_TaxPercentage
End Get
Set(ByVal value As Decimal)
m_TaxPercentage = value
End Set
End Property
Public ReadOnly Property PriceIncludingTax() As Decimal
Get
PriceIncludingTax = Price * (1 + (TaxPercentage / 100))
End Get
End Property
End Class
Module Client
Sub Main()
Dim product1 As Product = New Product
product1.Price = 100
product1.TaxPercentage = 8
Console.WriteLine(product1.PriceIncludingTax)
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
| Above 'Client' can't assign a value to property 'PriceIncludingTax'.
When we would make this property settable, what should then happen to Price and TaxPercentage when a PriceIncludingTax is set ? Should we adjust the TaxPercentage based on the old Price and the new PriceIncludingTax ? Or should we adjust Price based on the old TaxPercentage and the new PriceIncludingTax ? Both options are technically possible, but also abstraction wise illogical. It's better to first decide which states/properties are settable, and then to make all derived states/properties readonly.
If you're implementing a members and you have the option to chose between addressing a public accessible property and an encapsulated field ( which can reflect the same value ) chose to address the public accessible property. For instance you should be certain that 'TaxPercentage' delivers what it's stating to deliver, after all it is 'Public', so clients expect what it states. After setting 'TaxPercentage' to some value, clients expect that 'TaxPercentage' delivers that same value when reading this property. The encapsulated field to hold the property value ( in this case m_TaxPercentage ) on the other hand can hold any value, for any possible way of implementation. For instance it could hold value 40 or 0.4 for 40%, depending on what implementation is used. Nowhere is defined how this field ( in this m_TaxPercentage ) should represent the value for its corresponding property. This is why the getter of PriceIncludingTax uses TaxPercentage instead of m_TaxPercentage.
An alternative for using the ReadOnly Property is the use of a getfunction, this is also what the coding guidelines suggest in case the implementation is doing more than retrieving a value from a field : |
| Namespace Example5
Class Product
Private m_Price As Decimal
Public Property Price() As Decimal
Get
Price = m_Price
End Get
Set(ByVal value As Decimal)
m_Price = value
End Set
End Property
Private m_TaxPercentage As Decimal
Public Property TaxPercentage() As Decimal
Get
TaxPercentage = m_TaxPercentage
End Get
Set(ByVal value As Decimal)
m_TaxPercentage = value
End Set
End Property
Public Function GetPriceIncludingTax() As Decimal
GetPriceIncludingTax = Price * (1 + (TaxPercentage / 100))
End Function
End Class
Module Client
Sub Main()
Dim product1 As Product = New Product
product1.Price = 100
product1.TaxPercentage = 8
Console.WriteLine(product1.GetPriceIncludingTax())
Console.ReadLine()
End Sub
End Module
End Namespace Download Broncode |
Up
ReadOnly Fields
| Also fields can be declared ReadOnly.
These fields can only be assigned a value in the constructor.
This is used for frozen states. Don't confuse frozen states with constants. A frozen state can ( in contrary to constants ) be set at runtime ( although only in the constructor ). After setting its value, the 'ReadOnly' field never change ( just like constants ).
For more details about constructors and ReadOnly field, have a look at the topic about constructors. |
Up
WriteOnly Property
| It is possible to make a Property WriteOnly.
'WriteOnly' Properties have no getter. It's value can only be set.
Abstraction wise there are no situations in which this can be used. Why would a client be allowed to set a property to a certain ( for the client known ) value, but be disallowed to query the value it already knows ? |
This version ( published on 2008-06-24 ) is printed from http://www.studyvb.com, visit the website for more recent information.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|