Lesson 10 - Properties in VB.NET

Visual Basic .NET OOP Properties in VB.NET

In the previous lesson, Shared class members in VB.NET, we learned about Shared (static) class members in VB.NET. In today's tutorial, we're going to look at the other class members that we haven't gone over yet.

Properties

We often want to have control over how an object field changes from outside of the class. We could set the field as read-only or react to its changes somehow. Let's create a new project (name it Properties) and add the following Student class which will represent a student in a database.

Public Class Student

        Public fullName As String
        Public male As Boolean
        Public age As Integer
        Public fullAged As Boolean

        Public Sub New(fullName As String, gender As Boolean, age As Integer)
                Me.fullName = fullName
                Me.male = gender
                Me.age = age
                fullAged = True
                If age < 18 Then
                        fullAged = False
                End If
        End Sub

        Public Overrides Function ToString() As String
                Dim iAmFullAged As String = "I'm"
                If Not fullAged Then
                        iAmFullAged = "I'm not"
                End If
                Dim gender As String = "male"
                If Not male Then
                        gender = "female"
                End If
                Return String.Format("I'm {0}, {1}. I'm {2} years old and {3} of age.", fullName, gender, age, iAmFullAged)
        End Function

End Class

The class is very simple, the student has a name, gender, and age. The fullAged field is set according to the age and provides a more comfortable determination whether the student is of age from different places in the system. We'll use a Boolean value to store gender, True indicates that he's male. The constructor will determine whether the student is of age or not. The ToString() method has been altered to suit our needs. In a real world situation, it would probably just return the student's name. Let's create a student using the constructor:

Dim s As Student = New Student("Peter Brown", True, 20)
Console.WriteLine(s)

The output:

Console application
I'm Peter Brown, male. I'm 20 years old and I am of age.

Everything looks nice, but the fields are able to be re-written. Here, the object would no longer function properly (i.e. it has an inconsistent internal state):

Dim s As Student = New Student("Peter Brown", True, 20)
s.age = 15
s.male = False
Console.WriteLine(s)
Console.ReadKey()

The output:

Console application
I am Peter Brown, female. I am 15 years old and I am of age.

Certainly, we would want fullAged to be updated when the age is changed. Aside from that, no other field would need to be altered externally. Students don't usually change their genders or names. However, we'll keep them accessible for reading. In earlier parts of our course, we've used get methods to read Private fields. We would name them something like GetAge() and so on. We'll create get methods to be able to read certain fields and make these fields Private to prevent them from being modified from the outside. The class would now look something like this (I omitted the constructor and ToString()):

Public Class Student

        Private fullName As String
        Private male As Boolean
        Private age As Integer
        Private fullAged As Boolean

        ...

        Public Function GetFullName() As String
                Return fullName
        End Function

        Public Function GetFullAged() As Boolean
                Return fullAged
        End Function

        Public Function GetAge() As Integer
                Return age
        End Function

        Public Function IsMale() As Boolean
                Return male
        End Function

        Public Sub SetAge(value As Integer)
                age = value
                ' updating whether student is of age
                fullAged = True
                If age < 18 Then
                        fullAged = False
                End If
        End Sub

End Class

Methods used for returning values are very simple. When a user changes his/her age, our program recalculates the fullAged field. We made sure we can't set variables in any other way than what we want. We now control all the field changes and can work with them as needed. Our design must prevent all alterations of the internal state that would cause an object to malfunction.

Methods for returning values are called getters and methods for setting values are called setters. We could potentially add an EditStudent() method to edit other fields sort of like we did to the constructor. Essentially, a student's name, age, and other fields would be updated using this method. We could also validate values being set there since we would be able to handle all attempts to change certain values in one place. Implementing getters and setters manually is without a doubt hard work. Couldn't someone just do it for us? Yep, VB.NET is able to generate them for us! In that case, we're no longer talking about fields, rather properties.

The property syntax is very similar to the field syntax:

Public Property FullName As String

At first, it may seem as if we had declared a field. The property name is capitalized because it is actually a method (2 methods to be precise). We use the Property keyword to declare properties. In the example above, both the setter and the getter would be generated, and the property would be accessible both for reading and writing:

Console.WriteLine(object.FullName) ' reading
object.FullName = "John Black" ' writing

From the outside, the only significant difference against an attribute is that the first letter is uppercase. VB.NET internally generates a Private field and two public methods that are called automatically depending on the context (whether we read or write the value).

If you want to prevent all alteration of your variable from outside the class, you can make the property ReadOnly

Public ReadOnly Property FullName As String = "John Smith"

Unfortunately, this applies for us as well so we won't be able to assign anything to this property, ever from the inside of the class. Therefore, we won't uses that very often.

If we want to implement custom getter and setter, the syntax is as following:

Private _FullName As String
Public Property FullName As String
        Get
                Return _FullName
        End Get
        Set(ByVal value As String)
                _FullName = value
        End Set
End Property

When declaring custom getters and setters, we have to store the value somewhere. We store it into a private attribute which is usually prefixed with an underscore and has the same name as the property has.

If we didn't generate the setter part of the property, there would be no way to change the property from the inside nor the outside. If you want to prevent all alteration of your variable from outside the class, you would just make its setter private:

Private _FullName As String
Public Property FullName As String
        Get
                Return _FullName
        End Get
        Private Set(ByVal value As String)
                _FullName = value
        End Set
End Property

We'll use this very often and most of the properties in our classes will look like this from now on.

Let's take our example of the full-aged problem which must be re-evaluated when the student's age changes:

Private _Age As Integer
Property Age As Integer
        Get
                Return _Age
        End Get
        Set(ByVal value As Integer)
                _Age = value
                ' updating whether student is of age
                fullAged = True
                If _Age < 18 Then
                        fullAged = False
                End If
        End Set
End Property

First and foremost, we'll have to create a Private _Age field, the value will be stored there. We'll work with this field in the getter and the setter. If you were to use "Age", without the underscore, in the getter or setter, the program would get stuck in an infinite loop! Why? Well, take another look at the code above (hint: the method we are currently in has already been declared as that).

You cannot implement a custom getter and let the setter be generated automatically. They have to either both be generated automatically or both be implemented manually. To access the value being set in the setter, we use the value parameter. All properties had to be implemented like this until VB.NET added auto-implemented properties in version 4.0. As a matter of fact, we don't need any logic at all in the most of the properties. We'll treat the Age as we would treat a field from now (remember it is case sensitive). Re-assignment of the "Age" triggers the internal logic to update the fullAged field:

object.Age = 15 ' the fullAged field will update immediately as well

Likewise, we could implement a custom getter and log something.

Let's update our Student class so it'll use properties:

Public Class Student

        Private _FullName As String
        Property FullName As String
                Get
                        Return _FullName
                End Get
                Private Set(ByVal value As String)
                        _FullName = value
                End Set
        End Property
        Private _Male As Boolean
        Property Male As Boolean
                Get
                        Return _Male
                End Get
                Private Set(ByVal value As Boolean)
                        _Male = value
                End Set
        End Property
        Private _FullAged As Boolean
        Property FullAged As Boolean
                Get
                        Return _FullAged
                End Get
                Private Set(ByVal value As Boolean)
                        _FullAged = value
                End Set
        End Property

        Private _Age As Integer
        Property Age As Integer
                Get
                        Return _Age
                End Get
                Set(ByVal value As Integer)
                        _Age = value
                        ' updating whether student is of age
                        FullAged = True
                        If age < 18 Then
                                FullAged = False
                        End If
                End Set
        End Property

        Public Sub New(fullName As String, gender As Boolean, age As Integer)
                EditStudent(fullName, gender, age)
        End Sub

        Public Sub EditStudent(fullName As String, gender As Boolean, age As Integer)
                Me.FullName = fullName
                Me.Male = gender
                Me.Age = age
        End Sub

        Public Overrides Function ToString() As String
                Dim iAmFullAged As String = "I am"
                If Not FullAged Then
                        iAmFullAged = "I am not"
                End If
                Dim gender As String = "male"
                If Not Male Then
                        gender = "female"
                End If
                Return String.Format("I am {0}, {1}. I am {2} years old and {3} of age.", fullName, gender, Age, iAmFullAged)
        End Function
End Class

From now on, we will always use properties rather than fields since they allow us to encapsulate objects perfectly. In the .NET framework, all public class members are properties. For example, the Length property of a String. There's a general design guideline that we follow that states: values that are allowed to exit a class must be properties, and values that are internal and "non-editable", must be private fields. Overall, we don't use public fields. The whole class and demo app are, of course, available for download below the article. We can now remove the fullAged checking from the constructor since we now set the age using the Age property, and the FullAged property is updated automatically. Let's try the code which caused issues earlier:

Dim s As Student = New Student("Peter Brown", True, 20)
s.Age = 15
's.Male = False ' This line now causes an error and has to be removed
Console.WriteLine(s)

The output:

Console application
I am Peter Brown, male. I am 15 years old and I am not of age.

If we set the entire property as private, setters and getters will not be able to be marked as public.

In the next lesson, Date and time in VB.NET, we'll learn, how to work with date and time in .NET.


 

 

Article has been written for you by Michal Zurek
Avatar
Do you like this article?
1 votes
Thumbnail
All articles in this section
Object-oriented programming in VB.NET
Activities (10)

 

 

Comments

Avatar
Chen 琛
Member
Avatar
Chen 琛:25. April 8:22

Big salute to you! Michal, thanks for the great work! Time to read the next article

 
Reply 25. April 8:22
To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

1 messages from 1 displayed.