|
Properties |
|
|
Let us think for a moment about our student
class... How will the objects of this class be identified? Our class must have
the capability to handle Student ID, Name, Age, etc. The solution is simple, we can create public variables in the class to store these properties of a student. |
Public Class cStudent Public Age As Byte . . End Class |
|
To set the age we will do something like this:
Dim objStudent1 As New cStudent() Fine. Now consider the following:
Dim objStudent1 As New cStudent() or objStudent1.Age = 2000 We would not want the users of our class to be able to set wrong data or invalid data. But there is no way to control this if we allow the users to access the variables directly. So, what is the best solution for this? The answer is Properties. To store data of our object we would definitely require variables. These variables are called instance variables because they are created for each instance of the class. But, instead of giving direct access to instance variables, we will provide properties to the users of our class to access data. This way we will be able to check and control the value which is assigned. |
|
| Therefore, we will make our instance variables private so that they can not be accessed from outside the class: | Private iAge As Byte |
|
See, I have used the prefix 'i' before the variable name. I use this to differentiate instance variables from other elements. Our next step is to create a public property for Age: |
Public Property Age() As Byte Get Return iAge End Get Set(ByVal Value As Byte) If Value <= 12 Or Value >= 30 Then MsgBox("We do not accept students below 12 years and above 30 years", MsgBoxStyle.Exclamation, "Age not set") Else iAge = Value End If End Set End Property |
|
To access this property, we will use this code... Line 1: Set property - Age Line 2: Get property - Age |
Dim objStudent1 As New cStudent() |
|
A property has two parts: Get and Set. The get part of a property is accessed when the value of property is read like in line 3 above. Therefore, we need to return a value (which we want our users to read) when get is invoked. In this case, we return the value of iAge. Set part of the property is called when the user assigns some value to the property. The assigned value is passed to the Set code. Now see, we have decided to store the age in iAge variable. However, we do not want the users to set any age they want. Therefore, we have defined the criterion and applied it in the property. The value which users assign to the property is accessible to us through Value parameter. We can check the value and decide if we really want to assign it to iAge (as we have done above). This way we can maintain the integrity of our class. One more thing. We have used Public and Private in our instance variable declaration to make it accessible or inaccessible to the code outside the class. Public and private are access types or access specifiers which define the scope of a variable. Please check the following to see the available access types and the scope defined for each one.
Private - available only to the code within our
class Let's return back to properties. We have already learned how to create a property. What if you do not want the user to set or change a property but want to allow him/her to be able to get/see it. Yes, I am talking about readonly properties. |
|
| ReadOnly and WriteOnly Properties | |
| To understand this, let us assume that there is a property called TotalCreditsEarned and it is calculated by some complex method and users are not allowed to change its value directly. However, users can check/read the TotalCreditsEarned property. Let us assume that TotalCreditsEarned is calculated by some method and is stored in a private variable called iTCE. Using this information, we can write a read only property: |
Public ReadOnly Property TotalCreditsEarned()As Int16 Get Return iTCE End Get End Property |
|
Please note in the above code that to make a property read only, we use the ReadOnly keyword in property declaration and remove the set part of the property (we do not need this anyway in a read only property). Simple? Similarly, we can make a property write only by using the keyword WriteOnly instead of readonly and defining only the set portion. |
Public WriteOnly Property WOP() As DataType Set(ByVal Value As DataType) 'do something End Set End Property |
| Parameterized Properties | |
|
Now let us take one example. Suppose each student is evaluated on the basis of marks in VB, ASP and Java. To get or set these marks, we will have to create three private variables and three properties. Right? Let us see a better way to do so. We will keep 3 variables to store the values (yes, we can use array also), however, we will define only one property to access these variables. But the problem is - how will we know which subject user wants to access? See the code: I suppose code is quite self explanatory... Note that we have used a parameter (subj as string) to handle this case. |
Private iMarksVB As Single
Public Property Marks(ByVal subj As String) AsSingle
Set(ByVal Value As Single) |
|
To access this property, we will have to write
something like this: |
Dim objStudent1 As New cStudent() Dim MarksInVB As Single objStudent1.Marks("VB") = 55.5 'Line 1 MarksInVB = objStudent1.Marks("VB") ' Line 2 |
| Enumeration | |
|
There is a problem in above code. User must know that there are three subjects (VB, ASP, Java) and must use strings to represent them. If the spelling or letter case is wrong, then? VB.NET provides a very beautiful construct to handle such cases and I like to use it as much as possible - Enumeration. Have you ever noticed that while using the MsgBox function a list of all available buttons or icons appear automatically when you need to enter it? If not, then first of all do the following: Open a project and write - Msgbox "something" - in it and then put a comma (,). Did you see a list of all available buttons. Wouldn't it be nice if our class user gets a list like this (containing VB, ASP, Java, etc.) when he/she accesses the Marks property? And would you not like that when you are writing code for Get and Set, you also get the list while using Select Case statement? This reduces chances of error many times and provides a quick and easy interface for us and our users to work. Please see the code which demonstrates how to provide these features using enumeration. In the code note the following things:
|
Private iMarksVB As Single
Public Property Marks(ByVal subj As eMarks) AsSingle
Set(ByVal Value As Single) |
|
To use this property, see the code given here...
(The list of all available subjects comes automatically wherever this parameter
is used, for example, while using the property or while defining the property) Line 1: Set Property - Marks Line 2: Get Property - Marks |
objStudent1.Marks(cStudent.eMarks.VB) = 55.5 MarksInVB=objStudent1.Marks(cStudent.eMarks.VB) Write this code and try it out yourself once... |
|
Default Properties |
|
|
We need to write the following to access Marks property: objStudent1.Marks(cStudent.eMarks.VB) If we make Marks property the default property, we will be able to access it like this: objStudent1(cStudent.eMarks.VB) |
|
| Please see the code. Note that we have used Default keyword to make our property default. Simple. So we do not need to do anything to our property, except adding the keyword Default, to make it default property. Just a matter of one word!! |
Default Public Property Marks(ByVal subj AseMarks) As Single ... ... End Property |
|
Please note some obvious facts about properties:
This was all about properties. Let us move to methods in detail now. |
|
| Methods | |
| We have already seen how to create a simple method above. Let us consider it again: |
Public Sub Laugh() MsgBox(":)") End Sub |
|
Note the keyword Public here. It is an access specifier. Public means that the scope of this method is public, that is, we can call it from anywhere. Private access type limits the scope to the class in which the method is defined and Friend limits the access to the project in which the method is defined. I hope this must be clear by now. Methods can be of two types:
|
|
|
You have already seen how to define and use a
sub-routine above. Check out functions now: Note that we have used the keyword Function to define a function. The return type is specified in the definition itself. To return the result of the function, we use the Return keyword followed by the value we want to return. |
Public Function AverageMarks() As Single Return (iMarksVB + iMarksASP + iMarksJava)/3 End Function |
|
If we want to use parameters in functions or
sub-routines we can define the method as below:
Public Function FindPercentage(ByVal subj As eMarks) As Single |
|
| Optional Parameters | |
|
Look at the function above. We have assumed that the maximum marks for each subject are 150. If we want to give the user a choice to specify the maximum marks and if the user does not want we want to use 150, then what is the solution? Solution is function with optional parameters. Check the code: Note that in the code we have used an optional parameter MaxMarks. If a parameter is declared optional, the user may or may not enter a value for this. If the value is not specified by the user, default value is taken (150 in our case). It is compulsory to specify the default value for the optional parameters. A method can have any number of optional parameters, however, it should be noted that optional parameters must be the last in parameter list of a method. |
Public Function FindPercentage(ByVal subj AseMarks, Optional ByVal MaxMarks As Single = 150) As Single Dim result As Single Select Case subj Case eMarks.VB result = iMarksVB * 100 / MaxMarks Case eMarks.ASP result = iMarksASP * 100 / MaxMarks Case eMarks.Java result = iMarksJava * 100 / MaxMarks End Select Return result End Function |
|
To use this method, we can use following code: Line 1: Default value of MaxMarks would be taken, that is, MaxMarks=150 Line 2: User specified value is assigned to MaxMarks, that is, MaxMarks=100 |
objStudent1.FindPercentage(cStudent.eMarks.VB) objStudent1.FindPercentage(cStudent.eMarks.VB, 100) |
| One last thing about methods. We can pass objects as parameters to a method and also a method can return an object. To do this we just need to specify the class name in the method declaration (just as we did for enumeration). | |
| Shared Members | |
|
So far we have seen that the variables defined in
a class are created for each instance and hence are called instance variables.
Now, if we want to keep track of number of instances created then how can we do
so. Here come shared variables. Shared variables are variables which are shared
by all instances. In other words, we can say that shared variables belong to the
class and not the object. Similarly there can be properties and methods which do not depend on any object data. These may depend on shared data. Therefore, shared methods and properties cannot access instance variables, but they can use shared variables. Since shared members belong to the class and not the object, we do not need to create an instance in order to use shared members. We can simply access them as follows: Class.SharedMember An example of shared method is MessageBox.Show. Here, Show is the shared member of MessageBoxclass. Now, how to define shared members. Very simple. Simply put the keyword 'Shared' after the access type while declaring variables, properties, methods and events. |
|
| Events | |
|
We all have done programming based on events. In
this example also, we have used the Click Event of button. What are events?
Events are a mechanism through which the creator of class gives an opportunity
to the user of class to write code when something (some event) happens. To understand the application of this concept, let us assume that our class has a Save method which saves some data into a file. When the data is saved we want to notify our class user and allow him/her to perform further action, that is, write code which he/she wants to execute when data is saved. This gives our user great independence in performing whatever action he/she wants when data is saved, like simply showing a message box to the end-user or calling another method or copy the file in which data is saved for backup, etc. Did you note that there are a number of actions which user might want to perform when data is saved (the list can go up to infinity). Therefore, we cannot assume while designing a class that what action our class user might want to perform on some particular event and so it is wise to expose an event for the user to handle in a way he/she desires. |
|
| Creating Events | |
| The first step in creating an event is declaration. See the code. This line defines a public event named Saved. And remember there is no code because we are not going to write it!! If you want to add arguments to the event, you can mention them in the same way as we do for methodd. Pretty simple... | Public Event Saved() |
| Once an event is declared, the next step is to raise the event or fire the event at appropriate moment. This is done through RaiseEvent statement. Whenever we wish to fire an event, we use this statement. In this example, just after saving the data in Save method of the class. When the user calls the Save method, it saves the data and when data is completely saved, it fires the Saved event which is to be handled by the user. If you have declared event with arguments, pass the appropriate values in the arguments. These arguments will be available to the user of the class in event handler... |
Public Sub Save() 'code to save the 'data RaiseEvent Saved() End Sub |
|
To use this event, we need to do two things:
|
Dim WithEvents objStudent1 As New cStudent() |
|
To write the code to handle the event, we have to write an event procedure. An event procedure is nothing but a method which is called when the event is fired. But how can we associate a method with an event. One way is using Handleskeyword. This is the way the events are normally handled (our click event procedure also uses this way). Just write the method which you want to execute when event fires. Just add Handles objectName.EventName at the end of method declaration to associate that method with the event. However, this method must have the same number and type of arguments as declared in the event which the method has to handle (if the event has arguments)... If you want .NET IDE to automatically generate the method declaration, you can select the object from object list and then select the event from the event list, just as you do to write event procedure for other objects like button, textbox, etc. |
Private Sub objStudent1_Saved() HandlesobjStudent1.Saved 'Do whatever you want when data is saved MsgBox("Data Saved!!!") End Sub |
| Handling Multiple Events | |
|
Now, let us assume that we want to perform the same action when two different events occur. That is, we want to associate the same method with more than one events. Well, this can be done very easily in VB.NET. Just write all the events a method has to handle saparated with comma (,). Keep in mind that the rules of using Handles statement remain the same. If we want a method handleIt() to handle two events Saved and Loaded of object objStident1, we will use this code. |
Private Sub handleIt() HandlesobjStudent1.Saved, objStudent1.Loaded 'Do whatever you want when data is saved MsgBox("Data Saved!!!") End Sub |
| Event Association at run time | |
|
In all the examples above, we have associated a method with some event at design time. There can be situations in which you do not know which method handles which event, or, you create an object at run time and want to associate one of its event with some method. How can this be done? Before explaining this let us consider another case to feel the need to associate at run time. I have one application which loads the images from a folder at run time and shows them as thumbnails in picture boxes. When user clicks on any of the image a form opens with that particular image in full size. When the user clicks on this new form, the form unloads. Did you understand what I want to say? Now what I do to show the full view is, I create a form at run time, add picture box to it and show the selected picture in it. Remember all this is done through code at runtime. Now how to associate the method to unload this form with Picturebox's click event... This is what we are trying to see here. To associate an event with some method at run time, we use AddHandler statement. And to dissociate any event with its handler method at run time, we use RemoveHandler statement. Suppose we have a method XYZ(). To associate this method with objStudent1 object's Saved method at run time, we will use the following code: AddHandler objStudent1.Saved, AddressOf XYZ and to dissociate, we will use following line: RemoveHandler objStudent1.Saved, AddressOf XYZ As you can see, the first parameter used above is the event name and second parameter is address of the method. |
|