Since version 4, Visual Basic has offered some object-oriented (OO) programming abilities, although the implementation was less than perfect. With this release, VB .NET becomes the first truly OO version of VB. There is now full inheritance, along with other features such as abstraction, encapsulation, and polymorphism. VB .NET now even allows you to use classes written in other programming languages, such as C# or C++.
It is important to understand how object orientation will change your programs and the process of creating applications in VB .NET. It is a big shift in the way you'll write your applications and, because this is such a large topic, there are volumes of materials already written on object-oriented concepts and how they can be utilized effectively. Obviously, we can't re-create all of those works in a single chapter, so we'll focus on the ideas that most often come into play with VB .NET and how they can be used.
In this chapter, we go over each of these ideas, which may be new to VB programmers.
VB has supported abstraction since version 4, and it is actually a simple concept. It is a view of an entity that includes only those aspects that are relevant for a particular situation. In other words, it is the ability of a language to create 'black box' code that takes a concept and creates an abstract representation of that concept within a program.
For instance, suppose we want to create the code that provides services for keeping an employee information database. We'll need to store the following list of items:
One of the most important ideas to keep in mind is that we included several items in this list for basic information, such as Name and ID. However, we also have an action entity that will be used to increase or decrease salary. These actions are referred to as methods in VB .NET. In pseudocode, the object takes the following form:
Employee Object Name ID IncreaseSalary() DecreaseSalary() Salary End Employee Object
Encapsulation is the process of taking the abstract representation that we create and encapsulating the methods and properties, exposing only those that are totally necessary from a programmer's standpoint. The properties and methods of the abstraction are known as a member of the abstraction. The entire set of the members is known as the interface.
Simply put, this allows a developer to control the methods and properties that are available outside the object.
VB .NET is the first version of VB that supports inheritance, which is the idea that a class can gain the preexisting interface and behaviors of an existing class. In other words, a class can inherit these behaviors from the existing class through a process known as subclassing.
When an object is inherited, all of its properties and methods are automatically included in the new object. For example, suppose we look back at our Employee pseudocode object. Now, let's create a new object that tracks managers instead of employees:
Manager Object Inherits Employee Object ManagerPosition End Manager Object
This new Manager object will now have the same properties as the Employee object (an ID, Name, etc.), but also includes a property to detail the position the manager holds. This is a very powerful way to share the code that you have already written instead of re-creating the code.
Polymorphism was introduced with VB4. Polymorphism simply means having or passing through many different forms. That is, it is the ability to write one routine that can operate on objects from more than one class, while treating different objects from different classes in exactly the same way. An easy example would be to create several classes that inherit the Name property from the Employee class we have been looking at. Basically, this means that the Name property would be available in many different forms.
Polymorphism allows an inherited method to be overridden. Again, looking at the Employee object, we could create a new object that inherits the Employee object, but with a new method with the same name as the IncreaseSalary method we used earlier. Although the new object would then have the methods and properties of the original, because the new method exists, it executes it.
A class is used to define an object. It is a sort of template that you can use to define the properties and methods of your objects and is the structure that can contain events, constants, and variables. To create a class, you begin with the Class keyword and assign a name to create instances of the class. Any time we need to create a class in VB .NET, we simply put all the code for the class within the Class...End Class block. This is similar in many ways to the loops we looked at in the Chapter 5, Introduction to the VB .NET Language.
Statements within the class comprise its methods, properties, and events. Members declared as Private are available only within the class. Public members, on the other hand, are available outside the class and are the default declaration if neither is specified.
Methods in VB .NET are created using the Sub or Function keywords. A method created with Sub does not return a value, whereas a Function must return a value as a result. We've already looked at the concepts of a Function and Sub, so we won't spend any additional time on them. You can declare methods as follows:
Private: Only visible within the class
Friend: Visible by code within the project
Public: Visible by code outside the class
Protected: Available to subclasses
Protected Friend: Visible to the project and by code in subclasses
Properties store information in an object and can be specified by either public variables or as property methods. When properties are declared using a public variable, they are also referred to as fields. This method does not provide the ability to control (validate) reading and writing a property. Property methods allow you to control read and write operations of properties in a class using the ReadOnly keyword.
For example, let's look again at the Employee object we have talked about in pseudocode throughout this chapter. We'll create a simple class:
Class Employee Public ID As Integer = 1 Public Property Salary() As Integer ' This is a Property. Get Return Salary End Get Set(ByVal Value As Integer) NumWheelsValue = Value End Set End Property End Class
This doesn't take into account everything we would need to include in a real Employee object, such as name and so on, but the concepts for creating them are exactly the same as the previous code. We begin by creating a Public Property called Salary and then use Get/Set to retrieve or set the property value in our code. For example, after the class is available in the project, you can create a new Employee object as follows:
Dim clsEmployee As New Employee()
Then, you could assign a salary to an employee as follows:
clsEmployee.Salary = 500
We could also add methods to the example class:
Class Employee Public ID As Integer = 1 Public Property Salary() As Integer ' This is a Property. Get Return Salary End Get Set(ByVal Value As Integer) NumWheelsValue = Value End Set End Property Public Sub IncreaseSalary() 'We need code for increasing salary End Sub End Class
Again, these are very simple examples. Don't worry if all of this doesn't click at this time. We review these types of ideas as we use them in the book in real examples.
Constructors are methods of a class that are executed when a class is instantiated. They are very often used to initialize the class. To create a constructor, you simply add a public procedure called New() to your class. You can also use a parameterized constructor. This allows you to create a class that can have parameters passed to it when it is called.
Back to our employee class concept, we could create a constructor as follows:
Public Sub New() Salary = 500 End Sub
Using this example, when the class is initialized, we set the salary to a value of 500. This doesn't mean that it cannot be changed, but instead of assigning every employee a salary, they would begin with a salary of 500 that could be added to, subtracted from, or just changed completely.
We could also allow the user of the object to the constructor to pass in the initial value instead of assigning it to 500. We could use a parameterized constructor to do this. We add a parameter for the InitialSalary as follows:
Public Sub New(ByVal InitialSalary As Integer) Salary = InitialSalary End Sub
The user of the class could then create an object as follows:
Dim clsEmployee as New Employee (500)
This works well, but suppose that we want to offer a third option for the user of the class. Instead of assigning the salary by default to a value of 500, or using a constructor that required the user to assign it, let's use the Optional keyword to create an optional constructor:
Public Sub New(Optional ByVal InitialSalary As Integer = 500) Salary = InitialSalary End Sub
Now, if the user assigns a value, it overrides the default 500 value. If a value is not passed, the value is the default of 500.
Although these have been very simple examples, you can see how constructors can be utilized in your applications.
Overloading is one of the more appealing aspects of polymorphism. It allows you to create multiple methods or properties with the same name but with different parameter lists. You can change the parameters to completely different types. For instance, look at the following example Sub:
Public Sub MyMethod(X As Integer, Y As Integer)
To overload this method, you can come up with an entirely different list of parameters. For example, you can use Integer and Double:
Public Overloads Function MyFunction(X As Integer, Y As Double)
or Double and Integer:
Public Overloads Function MyFunction (X As Double, Y As Integer)
To put this into an example, let's suppose we want to create a class that multiplies numbers together. We could use the Overloads keyword to create the methods and then perform the appropriate action as necessary. Although it really doesn't make any difference in our simple example, we're going to create options for passing two integers or two real numbers. We could have made a single function that would have taken either of these, but for example purposes, we'll ignore this obvious fact:
Public Overloads Function Multiply(ByVal x As Integer, ByVal y As Integer) Return x * y End Function Public Overloads Function Multiply(ByVal x As Double, ByVal y As Double) Return x * y End Function
Then use these:
clsName.Multiply(1,5) clsName.Multiply(1.5, 5.5)
Now, when it is utilized, if two integers are passed (such as in the first example previously), the first function is executed. Interestingly, if one of the two parameters is a real number, the second multiply function is executed. This is because VB implicitly converts the Integer parameter to a Double data type in this instance. Similarly, if both values that are passed are real values, the second function is executed.
When you inherit a class, it allows you to use all of the methods and properties available in the class. Although this is obviously very useful, there might be times when you want to alter the inherited properties or methods. Instead of creating a new method or property with a new name, you can simply override the existing member, which is another feature of polymorphism.
To do this, you use the Overridable keyword in the original base class and then the Override keyword in the class derived from the original. For example, we'll use our original employee class:
Class Employee Public Overridable Function IncreaseSalary(byVal amt as Integer) As Integer Return amt+Salary End Function
Now, let's take a look at a new class derived from this one:
Class Employee2 Inherits Employee Public Overrides Function IncreaseSalary(ByVal amt As Integer) As Integer Return amt*2 End Function End Class
Although you will notice that the IncreaseSalary function that we created doesn't have any real program values, it is easy to use as an example. In the original class, we take the amount passed to the function and then add it to salary. In the inherited class, we take the same amount and double it. You will notice the Overridable and Overrides keywords in the previous code were the only additional requirements.
There are a few additional keywords that you can use when dealing with overriding members of a class. In addition to the two we already looked at (Overrides and Overridable), we can use the NotOverridable keyword to specify a method or property that cannot be overridden. You do not actually have to use NotOverridable because it is the default; so, unless you specifically use Overridable, it can't be overridden. You can choose to use NotOverridable or simply leave it blank-both are acceptable.
Another keyword is MustOverride. As its name indicates, if you use MustOverride, classes that are derived from a base class are required to override the property or method. For example, suppose we were to create a class that did mathematical calculations, but at the time of its creation, we didn't know what type of math was going to be used. We could simply create a MustOverride method in our class and then the classes that were derived from the original would be forced to override the method and use the appropriate math.
We'll look at one final area related to classes in VB .NET: Shared Members. If you create multiple instances of a class and then change the value of a property in one of them, it does not alter the value of the other. If you have a need to simultaneously alter members of multiple classes, you can create a shared member that allows you to create members that are shared among all instances of a class.
As we have been working our way through the basics of VB .NET, you may have been wondering how the classes are organized. After all, if you have methods from many different classes, it's likely that you could have some names that are identical. You wouldn't want to browse through hundreds of method names just to make sure that you didn't use the same names in your classes, not to mention the classes that you will ultimately use that others have created.
For example, let's look at a very common method name such as 'Open.' You might have a method named 'Open' for many different classes that all have unique code written for it. With this in mind, we need a way to organize the many classes and methods that are part of .NET so that they do not conflict with one another. This is where the .NET namespace comes into play.
Understanding the concept of the namespace is very simple as you have been using similar ideas in everyday life. For example, almost every town has a single or multiple McDonald's restaurant. You distinguish between the restaurants by their location. These addresses are similar to the way the namespace works in VB .NET because classes and methods in your application can be separated by locating them accordingly in a namespace.
For example, suppose we have a custom class with an Open method. The class is myclasses.clayton.fill. The built-in class System.IO has an Open method as well, related to handling the file input and output (I/O) features in VB .NET. So, if we were writing an application and wanted to include the System.IO features, we could do so as follows:
We could then use the class as follows:
Dim oFile As FileStream = New FileStream ("C: ext.txt", FileMode.Open, FileAccess.Read) Dim oStream As StreamReader = New StreamReader(oFile) MsgBox(oStream.ReadLine) oFile.Close() oStream.Close()
You'll notice that in the previous code, we begin with the Imports keyword. We could have typed the entire System.IO.FileStream out everytime we wanted to use it, but instead, we can use the Imports keyword to allow us to shorten it to just FileStream. Similarly, we use StreamReader instead of System.IO.StreamReader. This makes your code much easier to read and follow while saving you time while typing. We're not really interested at this time in what the previous code does, but are just using it as an example of how classes are organized and how the Imports keyword can be used in your future applications.
In this chapter, we covered the basics of object-oriented programming in VB .NET. We touched on abstraction, encapsulation, inheritance, polymorphism, classes, constructors, overloading, overriding, shared members and namespaces, and organizing classes. In Chapter 7, we look at strings, GDI +, and error handling.