Microsoft & .NETVisual BasicThe Book of Visual Studio .NET - OOP in VB .NET...

The Book of Visual Studio .NET – OOP in VB .NET Crash Course

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

A   V I S U A L   B A S I C . N E T   
C R A S H   C O U R S E

Object-Oriented Programming (OOP)

As mentioned earlier, Visual Basic did not meet the test as a true object-oriented
language that implements true object-oriented programming as defined by
abstraction, encapsulation, polymorphism, and inheritance. Visual Basic .NET
not only supports inheritance, but also supports a variety of inheritance implementations
including interface, forms, and implementation or polymorphism
inheritance.

Before you continue any further, let’s briefly discuss the four main concepts
of object orientation and the implementation code for each. Each brief discussion
is followed with an example that demonstrates the discussed OOP concept.

Abstraction

Abstraction is the easiest of the OOP concepts to understand and is often something
we implement naturally without realizing it. In short, abstraction is the
implementation of code to mimic the actions and characteristics of any realworld
entity.

The most commonly-used example for describing abstraction is the abstraction
of a person. Imagine that we want to create an object from a class that represents a
person. A person class will need to describe its characteristics through the implementation
of properties. Actions of the person class are performed by methods.

Encapsulation

Encapsulation is the programmatic equivalent of a black box. An actual black
box may have a switch and dials. Inside the box would be the mechanisms to
perform the actions provided by the black box.

We expose properties and methods through abstraction, but we implement
the actual workings of our component through encapsulation. A few encapsulated
actions might include data access, data validation, calculations, adding data
to an array or collection, or calling other methods or other components.
Exposing our components interface while hiding the component’s implementation
code effectively separates interface implementation from our black
box implementation. This separation helps to modularize components to perform
a more specific task while requiring minimal knowledge of how the black
box actually works.

One of the more useful applications of encapsulation is in making a complex
component. For example, your program may require interaction with a
third party system, but interaction with this system can only be achieved
through a complex API. Rather than requiring all developers on a project to
spend valuable time figuring out how to correctly use the third party API or
even find ways to misuse it, one developer could study the API then encapsulate
it in a component that exposes a less complex interface. This is a common practice
that saves time and reduces potential bugs.

Like abstraction, encapsulation isn’t as much a technology as it is a method
of code implementation. In the case of encapsulation, our method of implementation
separates the exposed interface from the actual implementation code.

Polymorphism

Abstraction is an interface implemented to represent a real-world object; encapsulation
is the implementation of a black box through interface and implementation
separation; and polymorphism is the ability to implement the interface of another
class into multiple classes or to implement multiple interfaces on a single class.
This method of implementation is referred to as interface-based programming.
A vehicle is a good example of polymorphism. A vehicle interface would
only have those properties and methods that all vehicles have, a few of which
might include paint color, number of doors, accelerator, and ignition. These
properties and methods would apply to all types of vehicles including cars,
trucks, and semi-trucks.

Polymorphism will not implement code behind the vehicle’s properties and
methods. (That’s the job of inheritance covered in the next section.) Instead,
polymorphism is the implementation of an interface. If the car, truck, and semitruck
all implement the same vehicle interface, then the client code for all three
classes can be exactly the same.

Implementing the vehicle interface only requires the declaration of properties and methods. To create a new interface, use t he Interface keyword in place of the Class keyword. The client implementing the new interface can do so by using the Implements keyword as shown in the example:

Implements Ivehicle

After using the Implements keyword, you will notice that Intellisense displays the properties and methods of the IVehicle interface. Using the Implements keyword will only give access to the properties and methods of the IVehicle interface; however, you must provide your own code behind the methods and property declarations to match the interface.

Inheritance

Inheritance is the ability to apply another class’s interface and code to your own
class. Remember, with polymorphism, you got the interface; however, you must
apply your own code. The power of inheritance is the ability to inherit code, saving
developers time. This type of inheritance is called implementation inheritance.
To inherit another class, use the Inherits keyword.

Visual inheritance is the ability to inherit another form’s look and feel onto
another. Remember, everything in .NET is a class, including forms. If you create
a project that exists in the MyApp namespace, create a form name MyBaseForm.
The following code will inherit the MyBaseForm within our new form:

Public Class MyNewForm
Inherits MyApp.MyBaseForm
End Class
Properties

Properties are part of a program’s interface and describe the characteristics of a
class. These properties hold information about a class or, when loaded into
memory, an object. Properties, as they exist in classes, are often referred to as
“data.” When a reference is made to a class’s data, you will know that the reference
is actually directed toward a class’s property.

To create a property, use t he Property keyword and t hen define the type of
property you are implementing. Properties can be read-only, write-only, or read
and writable. To define the characteristics of properties, use t he keywords
ReadOnly, WriteOnly, or supply no definition at all to implement both read and
write ability.

Visual Studio .NET makes properties easier to implement by adding the
basic shell of property code based on the property’s scope definition. Unlike
Visual Basic, Visual Basic .NET automatically supplies code for both read and
write functionality: “Get” for read ability method and “Set” for write access to a
property.

Create a new class, type the following code, and press ENTER:

Public Property FName() As String

Visual Studio .NET will automatically fill in the rest of the code that is
required by the FName property:

Get
Return m_FName
End Get
Set(ByVal Value As String)
m_FName = Value
End Set
End Property
Methods

Methods are the actions exposed by a class in the form of either functions or
sub-procedures. Sub-procedures and functions both execute code on behalf of
the calling application, but sub-procedures simply execute code while functions
execute code, then return a value.

The .NET Framework provides at least two new changes to how you can use
procedures. In Visual Basic, you could call a procedure without the use of
parameters, including procedures that required no parameters at all. The .NET
Framework requires parenthesis to follow all methods even when parameters are
not required. For example:

  • Visual Basic 6 method call:
    intResult = DoSomething
    
  • Visual Basic .NET method call:
    intResult = DoSomething()
    

Another change is the addition of the Return keyword. When returning a
value for a function in Visual Basic, you set the function’s name equal to the
value being returned. With Visual Basic .NET, you can se t the keyword Return
equal to a value and the value will be returned with the function. This is very useful
when making code more generic. For instance, you can easily cut and past a
method’s code without regard to another method’s function name because the
keyword Return is used for setting the method equal to a return value. Examples
of the old versus new method for returning values of a function are:

  • Visual Basic 6 method call:
    Public Function DoSomething() as Int32
    DoSomething = 10
    End Function
    
  • Visual Basic .NET method call:
    Public Function DoSomething() as Int32
    Return = 10
    End Function
    
  • If you look closely at a function’s supporting properties you will find that
    the Return keyword is used by default. You can set the function name equal to a
    given value.

    The third significant change is in how parameters are passed. Visual Basic
    passed a parameter value ByRef by default. The preferred method for passing
    parameter values is to explicitly define whether a value is passed by ByRef or
    ByVal. Finally, when using the Option keyword, you must define a default value
    similar to how C has worked for many years now.

    Declaration Options

    We have covered a few of the most common declaration methods including
    those that describe the scope of a property or method. Several description
    options will extend or restrict scope.

    Here is a list of the most commonly-used declaration options with brief
    descriptions of each:

  • Private: The Private keyword defines a variable or method as accessible
    only by code within the context of where the declaration occurred; outside
    code is not permitted access. Variables and methods defined as private are
    often referred to as member variables or methods, and commonly prefixed
    with an “m”.
  • Public: The Public keyword declares a property or method as accessible by
    anyone within the calling application or within the class itself.
  • Friend: The Friend keyword defines a property or method as accessible by
    members within the class it is declared in.
  • Protected: The Protected keyword defines a property or method as
    accessible only by members of its class or by members of an inheriting class.
  • Default: A Default property is a single property of a class that can be set as the
    default. This allows developers that use your class to work more easily with
    your default property because they do not need to make a direct reference to
    the property. Default properties cannot be initialized as Shared or Private and
    all must be accepted at least on argument or parameter. Default properties do
    not promote good code readability, so use this option sparingly.
  • Overloads:The Overloads property allows a function to be described using
    deferent combinations of parameters. Each combination is considered a
    signature, thereby uniquely defining an instance of the method being
    defined. You can define a function with multiple signatures without using
    the keyword Overloads, but if you use the Overloads keyword in one, you
    must use it in all of the function’s Overloaded signatures.
  • Shared:The Shared keyword is used in an inherited or base class to define
    a property or method as being shared among all instances of a given class.
    If multiple instances of a class with shared properties or methods are
    loaded, the shared properties or methods will provide the same data across
    each instance of the class. When one class alters the value for a shared
    property, all instances of that class will reflect the change. Shared properties
    of all instances of the class point to the same memory location.
  • Overridable:The Overridable keyword is used when defining a property or
    method of an inherited class, as overridable by the inheriting class.
  • Overides: The Overides keyword allows the inheriting class to disregard the
    property or method of the inherited class and implements its own code.
  • NotOverridable: The NotOverridable keyword explicitly declares a property
    or method as not overridable by an inheriting class, and all properties are
    “not overridable” by default. The only real advantage to using this keyword
    is to make your code more readable.
  • MustOverride: The MustOverride keyword forces the inheriting class to
    implement its own code for the property or method.
  • Shadows: The Shadows keyword works like the Overloads keyword except
    that with shadows we do not have to follow rules such as implementing the
    same signature. The Shadows keyword does not require the consent
    (override ability) of the inherited class to replace the property or method’s
    implementation code. A method does not have to be defined as overridable
    for the Shadows keyword to work.

Object Instantiation

When you drag and drop controls onto a Windows Form, you are using objects.
When you observe your code, you are looking at a class; when that code is
loaded into memory, at runtime, it is considered an object. The importance of
the distinction is simply to describe that a class is a template, while an object is
an instance of that template in memory. Also, many copies of the template can
exist in memory at the same time as objects.

Fortunately, we do not have to depend on the component designer to work
with classes; we can build our own classes and components. This is nothing new
for a moderately experienced developer; what is new is how Visual Basic .NET
permits us to instantiate classes.

Classic COM relied on the Windows Registry to store its exposed properties,
methods, events, and enumerations; a client application could only access
these exposed interfaces through the Registry. As a result, the way you instantiate
classes when using classic COM components in COM+ is very important.
Visual Basic .NET accepts a number of instantiation methods without performance
impacts, although all variables must first be diminished and then instantiated
before they can be used.

The two methods for instantiating classic COM are the CreateObject and
New keywords. CreateObject uses the Windows Registry to obtain the interface
of the class being instantiated. Because CreateObject depends on windows for
access to the register, COM+ can apply a context for use by the COM+ services.
The New keyword in classic COM also depends on Windows for access to the
Windows Registry. The catch is that it doesn’t always have to access the Windows
Registry to discover a class’s interface if the class resides inside the same component
as the calling class. Because the New keyword has no problem accessing a
class’s interface within the same component, a class can be instantiated by passing
COM+ services that would normally add a context or other component service.
While this will not prevent you from loading a class into COM+, to take full advantage
of COM+ services you should use the CreateObject keyword.

Having said all that, the CreateObject keyword cannot be used to instantiate
.NET classes, although it can be used to instantiate classes that exist within classic
COM components. Because .NET components don’t rely on the Windows
Registry, the New keyword is used when loading all .NET components.
Here are several examples of how you might define and load classes into
memory. First, the variable is diminished as MyClass:

Dim obj As MyClass

Second, you load the class “MyClass” into memory. An instance of a class
loaded into memory is referred to as an object. Notice there is no “Set” keyword
used.

Obj = New MyClass

Another method is to declare and instanciate an object in a single line:

Dim obj2 As MyClass = New MyClass()

Finally, you can implicitly diminish a variable with a class you are attempting
to load. This is the shortest method and is perfectly acceptable:

Dim obj3 As New MyClass

Early and Late Binding

Binding is something we do when diminishing a variable, though many developers
may not realize the importance of how they bind a class.

Early binding, often referred to as strong typing, refers to explicitly declaring
the class used to define a variable. Early binding has several benefits. For example,
when programming, Visual Studio .NET can give access to the class’s interface
with Intellisense which greatly reduces potential for typos and promotes
rapid development. Also, when early binding a class, the Visual Basic compiler
can enforce the proper use of a class’s interface by providing warnings and
refusing to complete the compile until the error is resolved. But performance
gains are probably the most important reason to bind early: Early binding allows
your program to access your class’s interface directly, rather than through the
Windows Registry or at runtime. If the compiler knows ahead of time which
classes you will be using in your application, it can make the appropriate compilation
optimizations.

Late binding can be useful when developing against non-existent components
or ones that are being developed. Late binding allows you to continue
compiling your code until the component is available; once the class is available,
you can modify your code to early bind. You might also use late binding when
you truly don’t know the object type that will be passed to your function, in
which case it is perfectly acceptable to accept any type of object.
Before late binding can occur, the Option Strict option must be set to off.
Option strict is off by default:

Option Strict Off

To declare a variable as lat e bound, simply diminish t he variable as type

object:
Option Strict Off
Dim obj As Object
'or
Dim obj As System.Object

The System.Object class is the class from which all other classes are derived.
While it has no specific characteristics that prevent it from acting as any other
class, it is used for late binding.

Components

A class defines something that can exist in memory. It defines an object’s interface
including properties, methods, events, and enumerations as well as implementation
code. An object is an instance of a class in memory; while a class may
exist only once, multiple instances of that class may reside in memory as objects.
When adding items to a project, you can add a “class” or a “component
class”. In essence, these are the same thing with one exception: a component
class implements the IComponent interface, enabling Visual Studio .NET to
drag non-visual controls, such as the timer control, onto a component designer.
Visual Studio .NET provides a designer for building components, which
allows you to drag visual controls onto your class or component, and begin coding.
For example, if you want to program a delay into your class, you can use a
component item with the designer to drag the timer control onto your component.
The implementation of a graphical designer (IE Component Designer)
and container are available to you when you selected “component class” as a
new item. Visual Studio creates your class by adding a line of code that inherits
everything your class needs to be a component, as follows:

Inherits System.ComponentModel.Component

Then the designer creates a components object using the IContainer interface
so that the designer can allow drag and drop capabilities:

Private components As System.ComponentModel.Icontainer

Simple OOP Examples

Now you’ll build an example application that employs abstraction, encapsulation,
polymorphism, and inheritance:

1. Create a new class library project named “PersonProj”.

2. Rename the Class1.vb file to “Person.vb”.

3. Add a new Windows Application project to the solution named “TestClient”.

4. Right- click on t he TestClient project and select Se t as StartUp Project.

Adding Abstraction

Now add abstraction:

1. Replace the default class in Person.vb with the following code:

Public Class clsPerson
Public FName As String
Public LName As String
Public FullName As String
Public BirthDate As Date
Public Age As Integer
Public TotalHours As Integer
Public Sub Work(ByVal intHours As Integer)
TotalHours += intHours
End Sub
End Class

2. Create a form that looks like Figure 7-2, and name it “frmAbstraction.vb.”
Use the parameters in Table 7- 4 to build the new Windows Form.

Creating a new Windows Form.

Table 7-4: Form Parameters

Control Property Value

Button Name btnSubmit
Text Submit
Textbox Name txtFName
Textbox Name txtLName
Textbox Name txtFullName
Textbox Name txtBirthDate
Textbox Name txtAge
Textbox Name txtHoursWorked
Label Name lblTotalHoursWorked

3. Right- click on t he TestClient project and select Properties. Change the Startup object to “frmAbstraction.vb”.

4. Add a r eference to the PersonProj. Right – click on t he TestClient project and select Add Reference. Select the Projects tab and press the “Select” button then press OK.

5. Add the following object declaration to the initialization of frmAbstraction form:

' Here we are initializing the Person class. Normally this would be done
' when the class was needed for data access but in this case we are using
' the Person class to maintain our data.
Dim objPerson As New PersonProj.clsPerson()

6. Add the following code to the submit buttons click event:

objPerson.FName = txtFName.Text
objPerson.LName = txtLName.Text
objPerson.FullName = txtFullName.Text
If IsDate(txtBirthDate.Text) Then
objPerson.BirthDate = CDate(txtBirthDate.Text)
End If
If IsNumeric(txtAge.Text) Then
objPerson.Age = CInt(txtAge.Text)
End If
If IsNumeric(txtHoursWorked.Text) Then
objPerson.Work(CInt(txtHoursWorked.Text))
End If
lblTotalHoursWorked.Text = "Total Hours Worked: " _
& objPerson.TotalHours.ToString

7. Now run the application.

You should be able to place any value you wish into the First and Last name
fields, then completely contradict yourself when filling in your full name. The
same should hold true for entering your birth date and age. This example
abstracts a person but does not hide any implementation; each time you press
the Submit butt on, the Total Hours Worked is summed and displayed.

Adding Encapsulation

The encapsulation example implements the clsPerson class and encapsulated
code, hiding the implementation code for all the properties and methods.
In the abstraction example, the user has to enter both their birthday and
age. As you encapsulate the implementation for the Person object, you will hide
the implementation of their age. Age will be derived from the person’s birth
date, thus preventing a user from creating an invalid age and birth date values.
Properties are also encapsulated, allowing the class to derive the full name from
the first and last names that have been entered.

1. Add a new Windows Form item named “frmEncapsulation.vb”.

2. Add the controls and parameters listed in Table 7- 5 to the frmEncapsulation.vb form.

Table 7-5: Controls for the Form

Control Property Value

Button Name btnSubmit
Text Submit
Textbox Name txtFName
Textbox Name txtLName
Label Name lblFullNameDisplay
Textbox Name txtBirthDate
Label Name lblAgeDisplay
Textbox Name txtHoursWorked
Label Name lblTotalHoursWorked

3. Create a new class in the Person class using the following code:

Public Class clsPerson2
Private m_FName As String
Private m_LName As String
Private m_BirthDate As Date
Private m_TotalHours As Integer
Public Property FName() As String
Get
Return m_FName
End Get
Set(ByVal Value As String)
m_FName = Value
End Set
End Property
Public Property LName() As String
Get
Return m_LName
End Get
Set(ByVal Value As String)
m_LName = Value
End Set
End Property
Public ReadOnly Property FullName() As String
Get
Return m_FName & " " & m_LName
End Get
End Property
Public Property BirthDate() As Date
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date)
If IsDate(Value) Then
m_BirthDate = Value
End If
End Set
End Property
Public ReadOnly Property Age() As Integer
Get
If DatePart(DateInterval.Year, m_BirthDate) = 1 Then
Exit Property
End If
Return DateDiff(DateInterval.Year, m_BirthDate, Now)
End Get
End Property
'Method for adding hours to m_TotalHours worked.
Public Sub Work(ByVal intHours As Integer)
m_TotalHours += intHours
End Sub
Public ReadOnly Property TotalHoursWorked() As Integer
Get
Return m_TotalHours
End Get
End Property
End Class

4. Add the following object declaration to the initialization of frmAbstraction form:

' Here we are initializing the Person class. Normally this would be done
' when the class was needed for data access but in this case we are using
' the Person class to maintain our data.
Dim objPerson As New PersonProj.clsPerson2()

5. Right- click and select Properties then change the StartUp object to “frmEncapsulation”.

6. Add the following code to the Submit button:

objPerson.FName = txtFName.Text
objPerson.LName = txtLName.Text
If IsDate(txtBirthDate.Text) Then
objPerson.BirthDate = CDate(txtBirthDate.Text)
Else
MsgBox("Please provide a valid Birth Date.")
End If
If IsNumeric(txtHoursWorked.Text) Then
objPerson.Work(CInt(txtHoursWorked.Text))
txtHoursWorked.Text = ""
End If
lblFullNameDisplay.Text = objPerson.FullName.ToString
lblAgeDisplay.Text = objPerson.Age.ToString
lblTotalHoursWorked.Text = "Total Hours Worked: " _
& objPerson.TotalHoursWorked.ToString

7. Now run the application and enter the information.

You’ll notice that your age is calculated for you so that it cannot contradict
what the age should be based on the birth date, and the full name is derived
from the first and last name.

Adding Polymorphism or Interface-based Inheritance

This example features an interface called IPerson and a class named Employee
that uses the IPerson interface:

1. First create a new Windows Form with the same controls as used in the
encapsulation example and name it “frmPolymorphism”.

2. Add a new Module to the PersonProj project and name it
“MyInterfaces.vb”.

3. Apply the following code to the MyInterface.vb module. The code defines

the interface.
Public Interface IPerson
Property FName() As String
Property LName() As String
ReadOnly Property FullName() As String
Property BirthDate() As Date
ReadOnly Property Age() As Integer
'Method for adding hours to m_TotalHours worked.
Sub Work(ByVal intHours As Integer)
ReadOnly Property TotalHoursWorked() As Integer
End Interface

4. Right- click and select Properties, then change the StartUp object to
“frmPolymorphism”.

5. Create a new class to the Person.vb module. You will use it to inherit the new interface:

Public Class clsPerson3
Implements IPerson
Private m_FName As String
Private m_LName As String
Private m_BirthDate As Date
Private m_TotalHours As Integer
Private m_HrRate As Integer
Private m_TotalPay As Double
Public Property FName() As String _
Implements IPerson.FName
Get
Return m_FName
End Get
Set(ByVal Value As String)
m_FName = Value
End Set
End Property
Public Property LName() As String _
Implements IPerson.LName
Get
Return m_LName
End Get
Set(ByVal Value As String)
m_LName = Value
End Set
End Property
Public ReadOnly Property FullName() As String _
Implements IPerson.FullName
Get
Return m_FName & " " & m_LName
End Get
End Property
Public Property BirthDate() As Date _
Implements IPerson.BirthDate
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date)
If IsDate(Value) Then
m_BirthDate = Value
End If
End Set
End Property
Public ReadOnly Property Age() As Integer _
Implements IPerson.Age
Get
If DatePart(DateInterval.Year, _
m_BirthDate) = 1 Then Exit Property
Return DateDiff(DateInterval.Year, _
m_BirthDate, Now)
End Get
End Property
'Method for adding hours to m_TotalHours worked.
Public Sub Work(ByVal intHours As Integer) _
Implements IPerson.Work
m_TotalHours += intHours
End Sub
Public ReadOnly Property TotalHoursWorked() As Integer _
Implements IPerson.TotalHoursWorked
Get
Return m_TotalHours
End Get
End Property
'Additional Properties:
'HrRate
Public WriteOnly Property HrRate()
Set(ByVal Value)
m_HrRate = Value
End Set
End Property
'TotalPay
Public ReadOnly Property TotalPay() As Double
Get
Return m_HrRate * m_TotalHours
End Get
End Property
End Class

6. Now run this example just as you ran the previous ones.
You will not notice a difference in how the application runs, although the
plumbing has changed quite a bit.

With this simple example, it is easy to question the usefulness of polymorphism.
However, if you were to continue building an application that dealt with
several aspects of a person, you might find polymorphism more helpful to use if
you had to deal with Employees, Customers, Managers, and Contractors.

Working with Inheritance

This inheritance example inherits the interface and implementation code of the
clsPerson3 class:

1. Add a new Windows Form item named “frmInheritance.vb”. Use the same
controls as we used in the encapsulation example.

2. Add the following code to the initialization section of the form:

' Here we are initializing the Person class. Normally this would be done
' when the class was needed for data access but in this case we are using
' the Person class to maintain our data.
Dim objPerson As New Person.clsEmployee()

3. Add the following class to the Person.vb module of the PersonProj project:

Public Class clsEmployee
Inherits clsPerson3
End Class

4. Right- click and select Properties, then change the StartUp object to
“frmInheritance”.

5. Now Run the inheritance example as you did the previous ones.
Notice that the clsEmployee class inherits the functionality of the clsPerson3
class, which in turn implements the IPerson interface. This example demonstrates
both polymorphism and inheritance that have been combined to form a
single solution.

Summary

In this chapter, you learned that Visual Basic has come a long way from a
reduced featured-set language that promoted RAPID application development
to a full featured language. Now employing full inheritance, Visual Basic promises
to aid in the delivery of enterprise level applications that may previously
have been better delivered in another OOP language.


# # #

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories