unimportant logo identifying Barry Cornelius

University of Oxford

Computing Services

OOP using VB.NET

  Author: Barry Cornelius Date: 23rd October 2004; first created: 18th October 2004

Contents

1. Introduction

2. The .NET Framework

2.1. Overview of the .NET Framework

2.2. The Common Language Runtime

2.2.1. The role of the Common Language Runtime

  • A runtime system is used to support the execution of programs
  • .NET provides a runtime system that is used by all .NET languages
  • Microsoft are providing .NET compilers for:
    • Managed C++
    • JScript
    • Visual Basic.NET
    • J#
    • C#
  • Others are providing .NET compilers for:
    • COBOL
    • Eiffel
    • Fortran
    • Haskell
    • ML
    • Perl
    • Python
    • Scheme
    • Smalltalk
    • ...

  • A .NET compiler writer can rely on the CLR:
    • to create new types;
    • to create and initialize objects;
    • to track references to objects and provide garbage collection;
    • to handle the calling of methods;
    • to manage the access to array elements;
    • to provide support for exceptions;
    • ...

  • A .NET compiler generates code in an intermediate language called MSIL.
  • A platform needs a CLR engine in order to run a file containing MSIL instructions.
  • There are CLR engines for most Windows platforms.
  • A project called Mono is building an open-source implementation of the .NET Framework.

2.2.2. The Common Type System

  • The CLR also includes a Common Type System (CTS).
  • The Common Language Specification (CLS) defines the aspects of the CTS that is supported by all .NET languages.
  • CLS says that each language must provide:
    • value types
      • simple types,
      • structure types,
      • enumeration types
    • reference types
      • class types,
      • interface types,
      • array types,
      • delegate types

2.2.3. The simple types

There is a set of simple types some of which must be provided. They are:

size C# Managed C++ Visual Basic.NET
System.Boolean 8 bool bool Boolean
System.Byte 8 byte char Byte
System.Int16 16 short short Short
System.Int32 32 int int or long Integer
System.Int64 64 long __int64 Long
System.Single 32 float float Single
System.Double 64 double double Double
System.Char 16 char __wchar_t Char
System.Decimal 128 decimal System::Decimal Decimal

2.3. A comprehensive class library

One of the significant features of the .NET Framework is that it comes with an enormous class library called the Framework Class Library (FCL). The types provided by the FCL can be used in any .NET language.

To begin with, you may want to become familiar with the following types:

System.Object
System.ValueType
System.String
System.IComparable
System.IEnumerable
System.Collections.ArrayList
System.Collections.Hashtable
System.Collections.IEnumerator

There are also types for accessing databases, using XML, and many more besides these!

2.4. Types associated with various applications

There are four main kinds of applications: console applications, windows forms applications, web form applications (ASP.NET pages) and web services. Each of these has associated types.

For example, if you are developing a console application, you will need the type:

System.Console

And, if you are developing a windows forms application, you will find the following types useful:

System.Windows.Forms.Form
System.Windows.Forms.Application
System.Windows.Forms.Button
System.Windows.Forms.TextBox
System.Windows.Forms.Label
System.EventArgs
System.EventHandler
System.Drawing.Point
System.Drawing.Size
System.Windows.Forms.MainMenu
System.Windows.Forms.MenuItem

Later, we will look in more detail at console applications and windows forms applications.

2.5. Other benefits of the .NET Framework

2.5.1. Language interoperability

  • Each .NET compiler
    • generates the same intermediate language,
    • uses the same simple types,
    • build new types in the same way,
    • ...
  • For these reasons, we can easily build programs written in a number of different .NET languages.
  • For example, a C# class can be derived from a VB class invoking constructors of the VB class and overriding some of its methods.

2.5.2. Tool support

  • Debuggers can support programs where the code has been written in different .NET languages.
  • IDEs (such as Visual Studio.NET) can use the CLR to provide information to the programmer developing a program.

2.5.3. Deployment

  • All the code and any information needed to run an application is provided in a collection of files.
  • An application is deployed by copying the files to an appropriate directory.
  • An application is removed by removing this directory.

2.5.4. Versioning

  • In .NET, a DLL file can be signed with a public key and a version number.
  • In this way, a computer can have more than one DLL with the same name.

3. VB using just the .NET Framework

The .NET Framework can be downloaded free of charge. In the future, it will be included as part of the Windows operating system.

Note: At the present time, there are two .NET Framework downloads: there is a .NET Framework Redistributable which software developers can give away with their products, and there is also a .NET Framework SDK which includes the compilers for Visual Basic.NET and C#. Although both of these downloads can currently be downloaded for free, I am unclear as to whether both will form part of future versions of the Windows operating system.

Rant: It is interesting to note that Microsoft are now giving away compilers: this once again makes it difficult for other software developers to offer competing products.

So you just need the .NET Framework in order to compile and execute Visual Basic.NET programs or C# programs. The compilers are in files called vbc.exe and csc.exe. On my laptop these files are in the directory:

E:\WINDOWS\Microsoft.NET\Framework\v1.1.4322

So, in a command shell window, add the appropriate directory to the path:

path=E:\WINDOWS\Microsoft.NET\Framework\v1.1.4322;%path%

Then use your favourite text editor to produce a program in VB.NET. For example, suppose you use a text editor to produce a file called Module1.vb that contains the following text. Note: ignore the line numbers that appear in this document: they do not form part of the programs:

0001: Imports System
0002: Module Module1
0003: 
0004:     Sub Main()
0005:         Console.Write("Centigrade value: ")
0006:         Dim tCentigradeString As String = Console.ReadLine()
0007:         Dim tCentigrade As Double = Double.Parse(tCentigradeString)
0008:         Dim tFahrenheit As Double = 32 + tCentigrade * 9 / 5
0009:         Console.WriteLine("Fahrenheit value: " & tFahrenheit)
0010:     End Sub
0011: 
0012: End Module

This program can then be compiled using the command line:

vbc Module1.vb

This produces a file called Module1.exe that can be executed in the usual way:

Module1

4. VB using Visual Studio.NET

Visual Studio.NET is Microsoft's integrated development environment for producing programs. It can be used to create programs written in Visual Basic.NET, C#, Managed C++, J# and JScript.

There are many ways in which Visual Studio.NET makes programming easier:

5. Object-oriented programming

5.1. Shared methods

The program given above includes four calls of methods. Two of these are calls of subroutines: these are the calls of Console.Write and Console.WriteLine. The other two calls are calls of functions: these are the calls of Console.ReadLine and Double.Parse.

Related methods can be grouped together using a class (or a structure). For example, the class Console contains methods associated with the keyboard/screen. You can deduce from the above program that it has methods called Write, WriteLine and ReadLine. And you can see that the structure Double has a method called Parse.

Another class that provides a lot of methods is a class called Math:

Double x = 2.0;
Double y = Math.Sqrt(x);

You call these methods using the notation:

ClassOrStructureName.MethodName(parameters)
In Visual Basic.NET, such methods are called shared methods: elsewhere they are called static methods or class methods. There is nothing new here: since the beginning of computing, we have had libraries of methods. So, shared methods are not exciting, and they have nothing to do with object-oriented programming.

5.2. Using types other than the simple types

One approach to writing a program is to identify the real-world objects (of the problem) that you need to represent in the program. Each real-world object can be in a number of states (i.e., may possess one of a number of values) and has a set of operations that can be performed on it.

Some of these real-world objects can be represented in a program by variables each of which is declared to be one of the simple types. For example, if our problem needs to represent the number of students in a lecture theatre, we can use an Integer in a VB.NET program in order to represent this real-world object. Or we might use a variable of type Double in order to represent the temperature of the air outside.

However, there are many real-world objects that cannot be represented in a VB.NET program by a value that is of a simple type. For example, we might want to represent a date in history, a point in two-dimensional space, the ISBN of a book, an e-mail address, the URL of a WWW page, and so on.

In most programming languages, a programmer can introduce new types to model these real-world objects. One way of doing this in a .NET language is to introduce a class declaration: we could introduce a class declaration for each of these classes of real-world objects.

However, we need not get into the details of writing class declarations straightaway: any .NET language can use any of the large number of classes defined in the Framework Class Library: maybe the FCL has a class that we can use.

5.3. Creating objects

Suppose you want to store a collection of strings. One way of doing this is to use a class of the FCL called ArrayList. This class allows you to create a flexible array of objects, an array which increases in size whenever necessary.

The ArrayList class provides several constructors. One of these allows you to specify the initial capacity of the ArrayList. Using this constructor, we can create an object using New:

0016:         Dim tLanguages As ArrayList = New ArrayList(2)

This makes the variable tLanguages point to an ArrayList object. It is a bit silly to give the ArrayList a capacity of 2, but this silliness will demonstrate that the ArrayList automatically increases in size when necessary.

The main purpose of a constructor is to give some initial values for aspects of the object being created.

5.4. Instance methods

The ArrayList class provides a method called Add that can be used to add an object to the end of an ArrayList. Here it is in action:

0017:         tLanguages.Add("Visual_Basic")
0018:         tLanguages.Add("C#")
0019:         tLanguages.Add("Managed_C++")
0020:         tLanguages.Add("JScript")

These calls of Add are unlike the calls of Write, WriteLine, Readline and Parse. Because, here before the dot, we put the name of the object to which we want the Add method applied. We might have several ArrayList objects in our program: however, in these statements, we want the Add method applied to the tLanguages object.

This kind of method is called an instance method because the method is being applied to a specific instance of the type.

The call of an instance method has the form:

VariableName.MethodName(parameters)

Suppose in our program we include a method to output an ArrayList of Strings:

0029:     Sub OutputStringList(ByVal pArrayList As ArrayList)
0030:         For Each tString As String In pArrayList
0031:             Console.Write(tString & " ")
0032:         Next
0033:         Console.WriteLine()
0034:     End Sub

This method can then be called in the following way:

0021:         OutputStringList(tLanguages)

This produces the output:

Visual_Basic C# Managed_C++ JScript

The ArrayList class also provides a method for reversing the elements of an ArrayList. This is another instance method. Here is a use of it:

0022:         tLanguages.Reverse()

If we call OutputStringList again:

0023:         OutputStringList(tLanguages)

we will get the output:

JScript Managed_C++ C# Visual_Basic

The ArrayList class provides several other instance methods. Here is a use of Insert and Sort:

0024:         tLanguages.Insert(2, "J#")
0025:         OutputStringList(tLanguages)
0026:         tLanguages.Sort()
0027:         OutputStringList(tLanguages)

These statements produce the output:

JScript Managed_C++ J# C# Visual_Basic
C# J# JScript Managed_C++ Visual_Basic

All of these calls are calls of instance methods: a method is being applied to an instance of the class.

5.5. Namespaces and Imports statements

So far we have used Console, Double, String and ArrayList. (Three of these types are classes; the other one is a structure.) Unless the organisation of names is more complicated, we would quickly run out of names. To avoid name clashes, each name is allocated to a namespace.

For example, Console, Double and String belong to the System namespace.

If we wish, we can fully qualify all the names we use:

Dim tCentigradeString As System.String = System.Console.ReadLine()

Some namespaces have subnamespaces. For example, the System namespace has a subnamespace called Collections. And ArrayList belongs to this subnamespace. So you could write:

Dim tLanguages As System.Collections.ArrayList = New System.Collections.ArrayList(2)

Obviously, it is tedious to use fully qualified names: they can be avoided by using an Imports statement. So, if your program starts with the lines:

Imports System
Imports System.Collections
Module Module1

you can use any of the classes of the System namespace or the System.Collections namespace without fully qualifying their names.

If you are using Visual Studio.NET (rather than using the vbc command), some Imports statements can be omitted. When using Visual Studio.NET, you do not need:

Imports System
Imports System.Collections
Imports System.Data
Imports System.Diagnostics
Imports System.Drawing
Imports System.Windows.Form
Imports Microsoft.VisualBasic

5.6. Providing our own types

We cannot just rely on others to produce all the types we need: we have to do some of this work ourselves. This is because some of the real-world objects that we will want to represent will be specific to whatever we are doing. We may need to represent people, bank accounts, grid references, ISBNs, audio CDs, and so on. And there are no types in the FCL for any of these.

In .NET languages, there are two kinds of types: value types and reference types.

A value of a value type is stored in a variable whereas for a reference type a variable points to the object in which the value is stored.

So the type Double is a value type whereas the type ArrayList is a reference type.

In .NET languages, there are two kinds of value types: structure types and enumeration types; and there are four kinds of reference types: class types, interface types, array types and delegate types.

Note: all of the simple types (e.g., Integer and Double) are structure types.

5.7. Providing a new class type in VB.NET

For an example of a class declaration, we now look at how we might represent a point in 2D space.

Note: although the FCL provides a type (System.Drawing.Point) for representing points in 2D space, for the sake of this exercise, we will pretend that it does not exist.

When we design a class declaration, we should think long-term: not about what we need in our current program but about what would be useful in this class so that it could also be used by other programs in the future.

There are two main characteristics to a type:

So when we are choosing how to represent something (e.g., points in 2D space) we need to consider these two characteristics.

5.8. A class type for representing 2D points

Here is a class type that can be used for representing 2D points:

0037: Public Class Point
0038:     Private iX As Integer
0039:     Private iY As Integer
0040:     Public Sub New(ByVal pX As Integer, ByVal pY As Integer)
0041:         iX = pX
0042:         iY = pY
0043:     End Sub
0044:     Public Property X() As Integer
0045:         Get
0046:             Return iX
0047:         End Get
0048:         Set(ByVal Value As Integer)
0049:             iX = Value
0050:         End Set
0051:     End Property
0052:     Public Function Distance() As Double
0053:         Return Math.Sqrt(iX * iX + iY * iY)
0054:     End Function
0055:     Public Overloads Overrides Function Equals(ByVal pObject As Object) As Boolean
0056:         If (pObject Is Nothing Or Not (Me.GetType() Is pObject.GetType())) Then
0057:             Return False
0058:         End If
0059:         Dim tPoint As Point = DirectCast(pObject, Point)
0060:         Return Me.iX = tPoint.iX And Me.iY = tPoint.iY
0061:     End Function
0062:     Public Overrides Function ToString() As String
0063:         Return iX & ":" & iY
0064:     End Function
0065: End Class

This class declaration needs to be put in a file called Point.vb.

In Visual Studio.NET, you add a new class (called Point) to a project by selecting Add New Item from the File menu, selecting the Class icon, changing the contents of the textbox to Point.vb, and clicking on Open.

Having created the class Point, how do we use it in a program? How do we create objects of this class, and use them?

Well, the class Point provides a constructor. It is shown on lines 40 to 43. So, in a program (e.g., Module1), an instance of the Point class can be created by:

0068:         Dim tPoint As Point = New Point(100, 200)

This produces:

The class Point also provides an instance method called ToString. So in our program we can call ToString as follows:

0069:         Dim tPointString As String = tPoint.ToString()
0070:         Console.WriteLine(tPointString)

This will output:

100:200

However, if a class declares a method called ToString, the ToString method will be called if we pass an object of that class to Write/WriteLine. So the above two statements can be abbreviated to:

0071:         Console.WriteLine(tPoint)

When you produce a class, it is very useful to provide a method called ToString.

In the following statements:

0072:         Dim tDistance As Double = tPoint.Distance()
0073:         Console.WriteLine(tDistance)

there is a call of an instance method called Distance. This will output:

223.606797749979

Suppose we now execute the statements:

0074:         Dim tAnotherPoint As Point = tPoint
0075:         Console.WriteLine(tAnotherPoint)

we will get the output:

100:200

We now have:

i.e., both variables are pointing to the same object.

This can be tested using the Is operator:

0076:         Console.WriteLine("Is: " & (tPoint Is tAnotherPoint))

This outputs:

Is: True

The class Point also provides an instance method called Equals. This can be called as follows:

0077:         Console.WriteLine("Equals: " & (tPoint.Equals(tAnotherPoint)))

This outputs:

Equals: True

If we create another point that happens to have the same value as tPoint then Is will return False whereas Equals will return True. So the statements:

0078:         Dim tClonePoint As Point = New Point(100, 200)
0079:         Console.WriteLine("Is: " & (tPoint Is tClonePoint))
0080:         Console.WriteLine("Equals: " & (tPoint.Equals(tClonePoint)))

output:

Is: False
Equals: True

Whenever you produce a class, it is important to provide a method called Equals that can be used to test whether two objects of that class have the same value.

In another demonstration that shows tPoint and tAnotherPoint are pointing to the same object, consider:

0081:         tAnotherPoint.X = 42
0082:         Console.WriteLine(tPoint.X)

These statements output:

42

Note: in the above declaration of the Point class, the iX and iY fields have been marked as Private. This means that a client of the class Point (such as Module1) is not allowed to access the iX and iY fields of any object. Indeed, if Module1 contains a statement like:

tAnotherPoint.iX = 42
it will not compile.

Instead, if it is necessary to allow a client to inspect/alter the value of a field, the class should provide a Property. In the above declaration of the Point class, a Property called X has been introduced that permits the value of the iX field to be got or set. By using a Property, you know that all accesses to the field will be done through the code of the Property. So you retain control. This is useful, e.g.:

If we now change the iX field of tClonePoint:

0083:         tClonePoint.X = 27
0084:         Console.WriteLine(tPoint.X)

the output:

42

again demonstrates that tPoint and tClonePoint are pointing to different objects.

5.9. Structure types

In C#, structure types are called structs. Chapter 11 of the 'C# Language Specification' says ‘Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are good examples of structs.’ So, if we want to represent points in 2D space in a program, it would probably be more appropriate to use a structure type rather than a class type.

A declaration of a structure type looks similar to that of a class type:

0087: Public Structure Point
0088:     Private iX As Integer
0089:     Private iY As Integer
0090:     Public Sub New(ByVal pX As Integer, ByVal pY As Integer)
0091:         iX = pX
0092:         iY = pY
0093:     End Sub
0094:     Public Property X() As Integer
0095:         Get
0096:             Return iX
0097:         End Get
0098:         Set(ByVal Value As Integer)
0099:             iX = Value
0100:         End Set
0101:     End Property
0102:     Public Function Distance() As Double
0103:         Return Math.Sqrt(iX * iX + iY * iY)
0104:     End Function
0105:     Public Overrides Function ToString() As String
0106:         Return iX & ":" & iY
0107:     End Function
0108: End Structure

Suppose we alter Module1 so that instead of it using the class called Point it uses this structure called Point. This will significantly affect the meaning of some of the statements.

For example, a value of a structure type is stored in the variable:

0111:         Dim tPoint As Point = New Point(100, 200)

And an assignment statement copies the value:

0117:         Dim tAnotherPoint As Point = tPoint

5.10. Differences between value types and reference types

The main ways in which value types are different from reference types are as follows:

As well as declaring our own value types (such as the structure type Point given in the previous section), there are hundreds of value types in the FCL. Some examples of enumeration types (from the FCL) are:

System.DayOfWeek                      System.IO.FileMode
System.Drawing.Drawing2D.DashStyle    System.Drawing.Drawing2D.FillMode
System.Globalization.DateTimeStyles   System.Windows.Forms.ButtonBorderStyle

Some examples of structure types (from the FCL) are:

System.DateTime                       System.TimeSpan
System.Drawing.Color                  System.Drawing.Point
System.Drawing.Rectangle              System.Drawing.Size

6. Turn On the Option Strict

One area where bugs often occur in programming is where variables are not typed or values are converted from one type to another. In VB.NET, it is possible to insist that all variables are typed and possible unsafe conversions are documented using DirectCast (or CType). This is done by setting the Option Strict to On.

At http://www.eggheadcafe.com/articles/20030801.asp, it says: ‘Unfortunately, in bringing out the final release of Visual Studio.NET, Microsoft bowed to the cries of millions of VB programmers and left Option Strict Off by default in all our VB.NET projects! Just about every professional author and programmer will tell you that you should ALWAYS set Option Strict to "On"!’

‘Fortunately, there is a very easy way to do this so that you won't forget. You are hereby strongly encouraged to go to the Visual Studio's Tools | Options menu, click the Projects | VB Defaults folder and set Option Strict and Option Explicit to On. You might then spend a bit more time writing CType-s or DirectCast-s, but you will avoid spending much more time tracking down some mysterious runtime errors. Many of your programs will also run FASTER.’

That does not seem to work for projects that you have already created. For such projects, do the following: From the Project menu, choose the last option which is the name of the project followed by the word Properties (e.g., PointClassTest Properties). Then click on Build. Then change the setting of "Option Strict" to "On".

7. Windows Forms applications

Standalone programs that read and/or write to a command shell window are boring: over the years, Visual Basic has led the way in making it easier to produce programs that have a graphical user interface (GUI).

Although it is possible to construct these programs yourself with a text editor, it is a lot easier to use one of Visual Studio.NET's wizards.

If, from within Visual Studio.NET, you choose the Windows application template, Visual Studio.NET will present a Form and invite you to add GUI components to the Form from a Toolbox.

Suppose we want a program that records the arrivals and departures of vehicles from a carpark. To the Form, we could add:

As you add GUI components to the Form, behind the scenes the wizard is adding code to a file called Form1.vb.

One key thing it does is to create variables in the program for each of the GUI components: they will be called TextBox1, Button1, Button2 and Label1.

Having added the GUI components to the Form, you can double click each button in turn. When you double click a button, Visual Studio.NET will open up the code of the Form1.vb file positioning you in the midst of the method responsible for handling clicks of that button. So if you double click the first button, it will put you in the body of a method called Button1_Click. You can then add the code you want executed when that button is clicked.

So I just provided lines 216 and 221 of the following code:

0128: Public Class Form1
0129:     Inherits System.Windows.Forms.Form
0130: 
0131: #Region " Windows Form Designer generated code "
0132: 
0133:     Public Sub New()
0134:         MyBase.New()
0135: 
0136:         'This call is required by the Windows Form Designer.
0137:         InitializeComponent()
0138: 
0139:         'Add any initialization after the InitializeComponent() call
0140: 
0141:     End Sub

          ...

0212: #End Region
0213: 
0214:     Private Sub Button1_Click(ByVal sender As System.Object, _
0215:             ByVal e As System.EventArgs) Handles Button1.Click
0216:         Label1.Text = TextBox1.Text + " has arrived"
0217:     End Sub
0218: 
0219:     Private Sub Button2_Click(ByVal sender As System.Object, _
0220:             ByVal e As System.EventArgs) Handles Button2.Click
0221:         Label1.Text = TextBox1.Text + " has departed"
0222:     End Sub
0223: 
0224: End Class

When we are using Visual Studio.NET, a lot of this code is hidden from us: on the screen, it is in the region labelled Windows Form Designer generated code. You can click on the + button in order to reveal the contents of this region.

You should be careful about altering the contents of this region. If you change the GUI components of the Form, it will automatically change the code of this region. Similarly, if you are clever enough to edit the code of the region to add the code for a new GUI component and it understands what you have done, it will automatically alter the contents of the Form.

8. Using an ArrayList to record the events

As well as confirming what has happened in a Label of the Form, perhaps we would like to record what has happened in a data structure. We could use an ArrayList for this.

We will need to refer to the ArrayList from several methods of the Form1 class and so an ArrayList variable (called iArrayList) can be declared as a Private variable of the class:

0225: Public Class Form1
0226:     Inherits System.Windows.Forms.Form
0227: 
0228:     Private iArrayList As ArrayList
0229: #Region " Windows Form Designer generated code "

An ArrayList object has to be created and assigned to the iArrayList variable. As we want this to be done just once, an obvious place for doing this is in Form1's constructor:

0231:     Public Sub New()
0232:         MyBase.New()
0233: 
0234:         'This call is required by the Windows Form Designer.
0235:         InitializeComponent()
0236: 
0237:         'Add any initialization after the InitializeComponent() call
0238:         iArrayList = New ArrayList
0239:     End Sub

And then the code of each method handling button clicks can be altered:

0335:     Private Sub Button1_Click(ByVal sender As System.Object, _
0336:             ByVal e As System.EventArgs) Handles Button1.Click
0337:         iArrayList.Add(TextBox1.Text)
0338:         Label1.Text = TextBox1.Text + " has arrived"
0339:     End Sub
0340: 
0341:     Private Sub Button2_Click(ByVal sender As System.Object, _
0342:             ByVal e As System.EventArgs) Handles Button2.Click
0343:         iArrayList.Remove(TextBox1.Text)
0344:         Label1.Text = TextBox1.Text + " has departed"
0345:     End Sub
0346: 
0347:     Private Sub Button3_Click(ByVal sender As System.Object, _
0348:             ByVal e As System.EventArgs) Handles Button3.Click
0349:         TextBox2.Clear()
0350:         For Each tString As String In iArrayList
0351:             TextBox2.AppendText(tString & vbCrLf)
0352:         Next
0353:     End Sub
0354: End Class

9. Using a CarPark class instead

The problem with the above solution is that the code handling the carpark is mixed up with the code handling the GUI. If there is a bug with the code for the carpark, then it is difficult to find the code because of all the code to do with the GUI.

It would be better to design a class for handling a carpark. If we are going to do this, then as before there are two questions to answer:

We have already decided an answer to the first question: a collection of number plates represented using an ArrayList. There are all sorts of operations that we could provide:

Here is the code of one possible CarPark class:

0355: Imports System.Text
0356: Public Class CarPark
0357:     Private iArrayList As ArrayList
0358:     Public Sub New()
0359:         iArrayList = New ArrayList
0360:     End Sub
0361:     Public Sub Arrive(ByVal pString As String)
0362:         iArrayList.Add(pString)
0363:     End Sub
0364:     Public Sub Depart(ByVal pString As String)
0365:         iArrayList.Remove(pString)
0366:     End Sub
0367:     Public Overrides Function ToString() As String
0368:         Dim tStringBuilder As StringBuilder = New StringBuilder
0369:         For Each tString As String In iArrayList
0370:             tStringBuilder.Append(tString & vbCrLf)
0371:         Next
0372:         Return tStringBuilder.ToString()
0373:     End Function
0374:     Public Function Size() As Integer
0375:         Return iArrayList.Count
0376:     End Function
0377: End Class

And here are the relevant parts of the Form1 class altered to use the CarPark class:

0378: Public Class Form1
0379:     Inherits System.Windows.Forms.Form
0380: 
0381:     Private iCarPark As CarPark
0382: #Region " Windows Form Designer generated code "
0383: 
0384:     Public Sub New()
0385:         MyBase.New()
0386: 
0387:         'This call is required by the Windows Form Designer.
0388:         InitializeComponent()
0389: 
0390:         'Add any initialization after the InitializeComponent() call
0391:         iCarPark = New CarPark
0392:     End Sub

          ...

0488:     Private Sub Button1_Click(ByVal sender As System.Object, _
0489:             ByVal e As System.EventArgs) Handles Button1.Click
0490:         iCarPark.Arrive(TextBox1.Text)
0491:         Label1.Text = TextBox1.Text + " has arrived"
0492:     End Sub
0493: 
0494:     Private Sub Button2_Click(ByVal sender As System.Object, _
0495:             ByVal e As System.EventArgs) Handles Button2.Click
0496:         iCarPark.Depart(TextBox1.Text)
0497:         Label1.Text = TextBox1.Text + " has departed"
0498:     End Sub
0499: 
0500:     Private Sub Button3_Click(ByVal sender As System.Object, _
0501:             ByVal e As System.EventArgs) Handles Button3.Click
0502:         TextBox2.Text = iCarPark.ToString()
0503:     End Sub
0504: End Class

10. Object-oriented programming revisited

By doing this, no longer is the code of the GUI mixed up with the code of the carpark. Indeed, it would now be easier to create several carparks: we would not have to duplicate the code for adding to the ArrayList or for visiting each element of the ArrayList, and so on.

The class declaration for CarPark hides an ArrayList and provides a number of methods for clients to access the ArrayList indirectly. This idea of hiding fields behind access methods is called information hiding or data encapsulation.

It may seem like a complicated way of providing an object and accessing it. However, you should view the class declaration as documenting a design decision. At the moment, we have chosen to represent a carpark by an ArrayList. At a later stage, we may feel that this is wrong: we may want to use some other representation. Since we have retained control over the access to the field of the class by making it private and providing access methods, we can make changes like this with only minimal impact to the code of the program: we know that the only code that needs to be changed is located in the methods of the CarPark class.

To demonstrate this, here is a different version of the CarPark class: in this version, the events are recorded in a MySQL database. The important thing to notice that the only code that needs to be changed is the code of the CarPark class: there are no changes to the Form1 class.

0505: Imports System.Text
0506: Imports System.Data.Odbc
0507: Public Class CarPark
0508:     Private iConnectionString As String = _
0509:             "DSN=Pdcl0bjc_CarParkVB;UID=dcl0bjc;PWD=XXXXXXX;"
0510:     Public Sub New()
0511:         Console.WriteLine("CarPark New")
0512:     End Sub
0513:     Public Sub Arrive(ByVal pString As String)
0514:         Dim tSQLString As String = _
0515:                 "INSERT INTO vehicles SET number = '" + pString + "'"
0516:         Console.WriteLine(tSQLString)
0517:         Dim tOdbcConnection As OdbcConnection = _
0518:                 New OdbcConnection(iConnectionString)
0519:         Dim tOdbcCommand As OdbcCommand = _
0520:                 New OdbcCommand(tSQLString, tOdbcConnection)
0521:         Try
0522:             tOdbcConnection.Open()
0523:             tOdbcCommand.ExecuteNonQuery()
0524:             tOdbcConnection.Close()
0525:         Catch pException As Exception
0526:             MessageBox.Show(pException.Message)
0527:         End Try
0528:     End Sub
0529:     Public Sub Depart(ByVal pString As String)
0530:         Dim tSQLString As String = _
0531:                 "DELETE FROM vehicles WHERE number = '" + pString + "'"
0532:         Console.WriteLine(tSQLString)
0533:         Dim tOdbcConnection As OdbcConnection = _
0534:                 New OdbcConnection(iConnectionString)
0535:         Dim tOdbcCommand As OdbcCommand = _
0536:                 New OdbcCommand(tSQLString, tOdbcConnection)
0537:         Try
0538:             tOdbcConnection.Open()
0539:             tOdbcCommand.ExecuteNonQuery()
0540:             tOdbcConnection.Close()
0541:         Catch pException As Exception
0542:             MessageBox.Show(pException.Message)
0543:         End Try
0544:     End Sub
0545:     Public Overrides Function ToString() As String
0546:         Dim tStringBuilder As StringBuilder = New StringBuilder
0547:         Dim tSQLString As String = "SELECT number FROM vehicles"
0548:         Console.WriteLine(tSQLString)
0549:         Dim tOdbcConnection As OdbcConnection = _
0550:                 New OdbcConnection(iConnectionString)
0551:         Dim tOdbcCommand As OdbcCommand = _
0552:                 New OdbcCommand(tSQLString, tOdbcConnection)
0553:         Try
0554:             tOdbcConnection.Open()
0555:             Dim tOdbcDataReader As OdbcDataReader = _
0556:                     tOdbcCommand.ExecuteReader(CommandBehavior.SequentialAccess)
0557:             While (tOdbcDataReader.Read())
0558:                 tStringBuilder.Append(tOdbcDataReader.GetString(0) & vbCrLf)
0559:             End While
0560:             tOdbcConnection.Close()
0561:         Catch pException As Exception
0562:             MessageBox.Show(pException.Message)
0563:         End Try
0564:         Return tStringBuilder.ToString()
0565:     End Function
0566:     Public Function Size() As Integer
0567:         Dim tNumRows As Integer = 0
0568:         Dim tSQLString As String = "SELECT number FROM vehicles"
0569:         Console.WriteLine(tSQLString)
0570:         Dim tOdbcConnection As OdbcConnection = _
0571:                 New OdbcConnection(iConnectionString)
0572:         Dim tOdbcCommand As OdbcCommand = _
0573:                 New OdbcCommand(tSQLString, tOdbcConnection)
0574:         Try
0575:             tOdbcConnection.Open()
0576:             Dim tOdbcDataReader As OdbcDataReader = _
0577:                     tOdbcCommand.ExecuteReader(CommandBehavior.SequentialAccess)
0578:             While (tOdbcDataReader.Read())
0579:                 tNumRows += 1
0580:             End While
0581:             tOdbcConnection.Close()
0582:         Catch pException As Exception
0583:             MessageBox.Show(pException.Message)
0584:         End Try
0585:         Return tNumRows
0586:     End Function
0587: End Class

The above code uses the Open Database Connectivity .NET Data Provider. In order to use ODBC, you will need to install an ODBC driver. As the above code connects to a MySQL server, I installed the MyODBC driver, onto the laptop from which I was running VB.NET.

11. Final thoughts

One book on Visual Basic.NET is 'Visual Basic.NET for Dummies' by Richard Mansfield (Wiley, 2003, 0-7645-2579-4). The Appendix of this book gives a useful summary of the issues involved in moving from Visual Basic 6 to Visual Basic.NET.

In this document, some of the ideas of object-oriented programming have been introduced. This has been done in the context of Visual Basic.NET, Microsoft's version of VB for the .NET Framework.

Although it introduces many of the basic ideas of object-oriented programming, this document has not mentioned inheritance, dynamic binding and interfaces.



Date: 23rd October 2004; first created: 18th October 2004 Author: Barry Cornelius.
This page is copyrighted