Вы находитесь на странице: 1из 272

244258241.

doc 1 od 272
vijaymukhi.com/documents/books/vbnet
Contents

Authors

Introduction


1.Visual Basic.Net - An introduction

2.Classes

3.WinForms

4.Access Modifers

5.Database Handling

6. XML

7. Exception Handling

8. Basics

9. Classes, Interfaces and
Structures

10. Parameters to Procedures

Introduction
The .NET Framework, encompassing a great new product called Visual Studio.NET, is tipped
to spur a revolution in the software industry. This is because, the .Net Framework and
Visual Stodio.Net have been designed with the Internet as their epicentre.

Visual Basic has been the most widely accepted programming language in the world, and
also enjoys the distinction of having the largest band of loyal programmers. Thus, Microsoft
was left with no choice but to integrate this product into the .NET Framework in the form of
VB.NET. In order to accommodate the large troupe of existing VB developers within this
framework, Microsoft has introduced a number of contemporary features to VB.NET, and
greatly ameliorated its web design facilities. VB.NET is also regarded as the easiest entry-
point into the .Net world, that provides succour to those who are terrifed of biting the bullet
of the Brave New World of technology.

244258241.doc 2 od 272
Microsoft has retained the heart and soul of the original VB product, while simultaneously
embellishing it with the latest developments available in software technology. This forms the
genesis of VB.NET. As a result, Visual Basic.NET is primarily an extension of the Visual
Basic programming language, which is shipped with the Visual Basic product. However, it is
a signifcant upgrade or improvement over VB and is far more fexible and powerful.

This book is for the dilettante, and aimed at anyone who is interested in learning VB.NET.
The approach that has been followed here is that simple applications are built frst, and
then, the code is deciphered to unveil the internal workings of the product.

However, in order to thoroughly appreciate the internal execution of the programs, there are
certain signifcant concepts of the language that need to be discerned frst. We have ferreted
out the relevant concepts and presented them in the most elementary manner.

This book converges predominantly around the language aspect, to provide enhanced
insights to the programmer into the innovative and improved features of VB.Net. We are of
the opinion that on learning the language, large applications can be designed with efortless
ease.

This book is also endowed with a generous sprinkling of error messages, since we believe
that by studying the cause of the errors that are generated by programming languages,
programmers are bound to become more astute.

We have ensured that your interest does not evaporate, by making the book as entertaining
and informative as possible. We have done our best to bring our aim of making you a good
VB.NET programmer, to fruition.

Finally, we leave it to you to decide whether the VB.NET product has really lived up its
expectations or not.


Minimum Requirements

The software requirements to successfully run all the programs in this book are

Operating System - Windows 2000, Windows XP
Microsoft IIS ver 5.0
SQLServer 2000
Visual Studio.Net


Visual Studio.Net
You can ask for your copy of this software from Microsoft by placing an order for the same
on their website.

SQLServer 2000
While installing the evaluation edition of SQLServer 2000, we have chosen the default
selected settings. The only modifcation made is in the Authentication Dialog Box.

You see two options
Windows Authentication mode
Mixed mode (Windows Authentication and SQL Server Mode)
244258241.doc 3 od 272

The default option selected is Windows Authentication mode. We have instead selected Mixed
mode (Windows Authentication and SQL Server Mode). Once this option is selected, the
password text boxes for the 'sa' user gets activated. As we would prefer using a blank
password in our programs, we select Blank Password. On selecting this option, the text
boxes get disabled again.
1. Getting Stated

In this book, we work under the basic assumption that you have no inkling about any of the
programming languages, and VisualBasic.Net in particular. But, you would invariably have
heard people fantasizing about the great new product called Visual Studio.Net, which is in
the reckoning to bring about a revolution in the software industry.

So, let us get to the meat of this product. We shall gain a meticulous understanding of this
language and its features, and only then shall we decide whether the claims made by the
populace are justifed or not. We could keep extolling the virtues of the fner things in life,
but we'd rather get down to brass-tacks straightaway. We assume that you have a copy of
Visual Studio.Net installed on your machine.

To launch Visual Studio, click on the ubiquitous Start Button in Windows. (In our case, we
have installed Windows 2000). Then, click on Programs, followed by Microsoft Visual
Studio .Net. Finally, select the option of Microsoft Visual Studio .Net. This is shown in the
Screen 1.1.

Sceen 1.1

Shortly thereafter, a window pops up, showing Visual Studio.Net in all its glory, as shown in
screen 1.2.

244258241.doc 4 od 272
Sceen 1.2

Hey, hang on! Could there be something amiss with what you are doing? Your copy of Visual
Studio .Net could be displaying something totally diferent!! Yes, this could be a distinct
possibility!

One of the salient features of present day software is that it can be customized to a large
extent. This is why the fnal appearance of a product could be drastically diferent from what
it originally looked like, when freshly taken out of the box. Thus, the screen 1.2 will never
look identical on all the machines. We shall explicate these diferences in due course, but for
the moment, we are exceedingly inclined towards embarking upon the development of a
small application or project. But before venturing any further, close all the child windows by
clicking on the x sign.

Then, click on the menu option File, followed by New, and fnally Project. This becomes
evident in screen 1.3.

Sceen 1.3
244258241.doc 5 od 272

The above actions will result in the display of the Dialog box titled "New Project". This is
shown in screen 1.4.

The advantage of using Visual Studio .Net is that diverse applications, each using a diferent
programming language, can be developed simultaneous, under a single streamer.

This explains why three language options are present in the frst pane of the dialog box, viz.
Visual Basic, Visual C# and Visual C++.

Sceen 1.4

The option of Visual Basic project is listed frst. Hence, it is highlighted by default. This
signifes the priorities of Microsoft, and is the very raison de etr of this book!

A perfect analogy for Visual Studio .Net is that of a glass, which can be used to drink either
water or juice or wine. In a similar fashion, under the single roof of Visual Studio .Net,
various programs developed in diferent languages, can be written. The language used is
simply not an issue.

The second pane titled 'Templates' determines the type of application that would eventually
be created. This could be an executable fle running under Windows, or a Web Application
running a web server.

Since we are nave about this product, we select the option of Windows Application. This
option is selected by default.

The next task is to specify a name for the project. We have chosen the name 'vvv', since we
sincerely believe that it will bring us good tidings on our very frst application. We have used
our newly created folder called 'v1' as the location for creating the application. You are at
liberty to choose any folder that you fancy.

244258241.doc ! od 272
Sceen 1.5

After specifying all the details as shown in screen 1.5, click on the OK button.

This brings us to Screen 1.6, where we encounter an empty form.

Sceen 1.!

Now, in order to view the output of our handiwork, click on the menu option Debug, and
then on Start. This is shown in screen 1.7.

244258241.doc 7 od 272
Sceen 1.7

This ignites the excitement of Visual Studio .Net, and it starts processing the request.
Finally, as the outcome of the operation, it displays an empty form, as seen in screen 1.8.
This is no mean achievement for people like us, considering the fact that we have not written
even a single line of code yet!

Sceen 1.8

Close this form window by clicking on the x sign on the right hand side. This will revert us
back to the form in Visual Studio .Net. The next task that we venture upon is, to display a
button on the form. To accomplish this, click on the menu option View, and then, on the
option of ToolBox, as shown in screen 1.9.

244258241.doc 8 od 272
Sceen 1."

This option brings up a toolbox containing a list of objects or controls. The toolbox window
is visible on the left hand side of the screen, as revealed in screen 1.10.

Sceen 1.1#

Now, simply click on the control labelled as Button to select it, and then, drag and drop it
into the form. Screen 1.11 displays the position where we have dropped our button.

244258241.doc " od 272
Sceen 1.11

Then, run the application in the customary manner by clicking on the menu Debug, and
then, click on Start. Screen 1.12 confrms that the form now contains the button in it. Pat
on the back! Having covered just a couple of pages, we have already placed a button on the
form.

Sceen 1.12

The shortcoming of our present endeavour is that, we are clueless about what is going on
behind the scenes. Clicking on the OK button in the New Project dialog box, results in the
generation of considerable amount of code by the Visual Studio .Net framework. Apparently,
we have merely clicked on the ToolBox, which is a User Interface tool; and then, we have
dragged and dropped a button in the form. However, in reality, ample code has been
generated in the background to accomplish this seemingly simple task.

We are convinced that prior to forging ahead with the task of building complex applications
using Visual Studio .Net, there is a need for discerning the code that it generates. Also,
244258241.doc 1# od 272
along the way, we shall keep reverting back to the Visual Studio .Net framework, to
demonstrate as to how it has made a programmer's life more easygoing. However, you have
to learn a programming language that is to be used with it, since it is a fundamental fact
that Visual Studio .Net cannot build customized applications by itself. It is the task of the
programmer to program it to satisfy the specifc requirements.

So, we start by writing the smallest Visual Basic program. As is customary in all our books,
we shall refrain from attempting to impress you with our knowledge of programming.
Instead, we shall proceed systematically, a single step at a time. So, here we go!

First, create a folder named il on your hard disk. Then, using a text editor such as Notepad,
create a fle called a.vb, with the following contents in it:

a.vb
Module zzz
End Module

To execute the above code, go to the Visual Studio .NET Command Prompt (Start-> Program-
> Visual Studio .Net-> Visual Studio .Net Tools-> Visual Studio .NET Command Prompt), and
run a program called vbc. We achieve it as follows:

c:\il>vbc a.vb

This action of ours results in the following error message:

vbc : error BC30420: 'Sub Main' was not found in 'a'.

Every Visual Basic program must be enclosed within the words 'Module' and 'End Module'.
There is no rational explanation for this prerequisite. So, we accept it as the dictum. Every
Module requires a name. So, we have chosen the name 'zzz'. This name has been
deliberately chosen to demonstrate that the name per se, is not very signifcant. Any name
would sufce, as long as one is present. An empty module is forbidden. Further, the error
message displayed earlier clearly mandates the presence of a function or a sub-routine
called Main.

a.vb
Module zzz
Sub Main()
End Sub
End Module

After we insert two lines within the Module, the compiler successfully compiles without any
hiccups. In the directory, you will see a fle called a.exe, which when executed, does not
display anything.

Visual Basic is a case-insensitive language. However, we still follow the Microsoft convention
of writing the word Module with a capital M, even though we are at liberty to determine our
own capitalization rules.

After having attended to the frst rule of Visual Basic, i.e. enclosing the code within the
words 'Module' and 'End Module', we progress onto the second rule, which insists on the
presence of a sub-routine called Main. The word 'sub' is a short form for the term sub-
routine, which takes a name along with it. It is merely a collection of code.
244258241.doc 11 od 272

A sub-routine is created in a manner similar to the creation of a module, where we begin
with the word Sub, followed by the name of the sub-routine, i.e. Main. Finally, the
subroutine has to conclude with the word 'End', followed by the word 'Sub'. A 'Sub' can have
a pair of open and close brackets. However, they are optional. So, on odd days we write 'Sub'
with brackets in our programs, while on even days, we omit them ;-).

The Visual Basic language is verbose and rather lax in its rules. Now, let us write a program
that displays a string.

a.vb
Module zzz
Sub Main()
System.Console.WriteLine ("Hello")
End Sub
End Module

ut!ut
"ello

On compiling and executing the above program, we are greeted by the word "Hello" in the
output. It has been an ancient programming tradition wherein, the frst program in any
programming language displays the word "Hello". The word "Hello" gets displayed on the
screen because a function has been executed or called.

In a programming language, a function name constitutes a word, followed by a pair of round
brackets.

Thus, Main is a function, since it ends with a pair of round brackets. However, there is a
subtle diference, which is:
In the case of Main, we were creating a function or a sub-routine, since the line
started with the word 'Sub'.
In the case of System.Console.WriteLine ("Hello"), the word 'Sub' is not present.
Hence, it construes that a function or subroutine is being called for execution.

There is a minor distinction between a subroutine and a function, which we shall attend to
later on, in the chapter.

The name of our function i.e. System.WriteLine.Console, is considerably long. We need not
torment ourselves about the details of how this function has been written, at this stage. We
only have to be conscious of the fact that it requires some words to be inserted within
double quotes, which it will display on the screen.

Since we have specifed the word Hello within double quotes, the console displays the word
"Hello". This is the mechanism of passing data or parameters to a function. This function is
one of the innumerable ones that are available in Visual Basic. We can use them on multiple
occasions in our code.

a.vb
Module zzz
Sub Main
System.Console.WriteLine ("Hello")
System.Console.WriteLine (100)
End Sub
244258241.doc 12 od 272
End Module

ut!ut
"ello
#00
A single function is capable of embodying multiple lines of code. In the above program, we
have called the function System.Console.WriteLine twice:
On the frst occasion, we have passed a string or a sequence of letters of the alphabet
as a parameter.
On the second occasion, we have passed it a number.

The function dutifully prints out both the values without complaining at all.

a.vb
Module zzz
Sub Main
System.Console.WriteLine (vijay)
End Sub
End Module

$rror
c:\il\a.vb%3& : error BC304'#: (a)e 'vi*a+' is not declared.
S+ste).Console.,rite-ine %vi*a+&

In the WriteLine function, we have specifed the word vijay, without enclosing it within
inverted commas. The Visual Basic product or compiler reverts back with an error,
expressing its ignorance about the name vijay. It expects it to be declared explicitly.

a.vb
Module zzz
Sub Main
dim vijay
vijay 100
System.Console.WriteLine (vijay)
End Sub
End Module

ut!ut
#00



To create or declare any valid name, the line must begin with the word DIM, followed by the
name, thereby, informing VisualBasic.Netthat a name is being created. Thus, 'DIM vijay'
signifes that the name vijay is being declared. These names are created so that they can
store values in them. On the next line, we have specifed a value of 100 to be stored in the
name vijay.

An elementary rule in all programming languages is that, a number or a string may be
substituted by a name that holds the value. Therefore, when the function WriteLine is
furnished with the name vijay, no error is generated. This is because, the framework frst
identifes the value contained in it. Since vijay holds the value of 100, it is displayed on the
screen.

a.vb
244258241.doc 13 od 272
Module zzz
Sub Main
dim vijay
vijay 100
System.Console.WriteLine (vijay)
vijay !00
System.Console.WriteLine (vijay)
vijay vijay " 10
System.Console.WriteLine (vijay)
vijay vijay " 1
System.Console.WriteLine (vijay)
End Sub
End Module

ut!ut
#00
200
2#0
2##

As was done in the program above, we create a name vijay and assign it a value of 100.
Then, using the WriteLine function, the value is displayed. vijay is then re-assigned a new
value of 200, which is also displayed. Thus, the value stored in vijay can vary. Due to this
ability to hold varying values, words such as vijay, are termed as variables.

On the next line, we have performed an arithmetic operation by presenting the statement
vijay = vijay + 10. On encountering a line containing an 'equal to' sign =, initially all
attention is riveted on the expression that is on the right side of the sign. This expression is
'vijay + 10'. So frstly, the value of vijay is evaluated to obtain a value of 200. Then, 10 is
added to it, in order to obtain a result of 210.

This value is now assigned to the variable on the left hand side of the 'equal to' sign, i.e.
vijay, thereby updating its value. Thus, when the variable vijay is displayed, it shows the
value of 210. In the next round, the value of the variable is increased by 1, thus, making the
fnal value as 211.

The concept of variables is one of the pillars on which the programming world rests. Here, a
word or name holds a value, which can keep fuctuating.

a.vb
Module zzz
Sub Main
dim vijay
vijay 100
System.Console.WriteLine (vijay)
vijay "#i"
System.Console.WriteLine (vijay)
End Sub
End Module

ut!ut
#00
.i

244258241.doc 14 od 272
In this example, the variable vijay is frst assigned a numeric value 100. Then, it is assigned
a string value of "hi". Nobody complains and both values get displayed. Thus, we have the
license to change the data type of the value that the variable can hold.

a.vb
Module zzz
Sub Main
dim vijay as inte$er
vijay 100
System.Console.WriteLine (vijay)
vijay "#i"
System.Console.WriteLine (vijay)
End Sub
End Module

ut!ut
#00

/n.andled $0ce!tion: S+ste).InvalidCast$0ce!tion: Cast fro) strin1 2.i2 to t+!e 'Inte1er' is
not valid. 333> S+ste).4or)at$0ce!tion: In!ut strin1 was not in a correct for)at.
at Microsoft.5isualBasic.Co)!ilerServices.6ouble7+!e.8arse%Strin1 5alue9
(u)ber4or)atInfo (u)ber4or)at&
at Microsoft.5isualBasic.Co)!ilerServices.Inte1er7+!e.4ro)Strin1%Strin1 5alue&
333 $nd of inner e0ce!tion stac: trace 333
at Microsoft.5isualBasic.Co)!ilerServices.Inte1er7+!e.4ro)Strin1%Strin1 5alue&
at ;;;.Main%&

The previous program does not demonstrate the conventional technique of programming,
because a variable must essentially represent only a single type during its lifetime. To
maintain absolute consistency, the data type is specifed while creating the variable.

This is achieved by adding the word 'as' after the DIM variable, followed by a predefned data
type. vijay is assigned the data type of integer, which implies that the variable vijay shall
store only numbers or integers.

After displaying the number that it contains, the variable vijay is then initialized to a string
value of "hi". The earlier program had not protested under similar circumstances.
However, now we come across a mammoth dialog box displaying an error message. When we
click on No, we observe the above error on the console.

This error or exception enucleates the fact that, we are not empowered to specify a string
value for a variable that has been declared to be of type integer. Henceforth, we shall declare
all our variables with a data type.

a.vb
Module zzz
Sub Main
dim i%j as inte$er
i 10
System.Console.WriteLine ("&0' &1'"% i% j)
End Sub
End Module

ut!ut
#0 0

244258241.doc 15 od 272
In a single stroke, we have the ability to create as many variables as we wish, separating
each one of them with a comma. The above example has two integer variables named i and j,
which have been declared together. The variable i is assigned a value of 10, while j is not
initialized at all. In the same manner that was used to create two variables simultaneously,
we now wish to print their values too in a single stroke.

To accomplish this, the WriteLine function has been modifed and assigned a string that has
the numbers 0 and 1 enclosed within curly braces. This string parameter is followed by the
two variables i and j, separated by commas. They are extra parameters.

The WriteLine function replaces the frst curly brace of 0, with the value of the frst
parameter after the string i.e. i, and the second curly braces of 1 with the second parameter
after the string, i.e. j. Since the value of the variable i is 10, and the value of the variable j is
0, the output that is displayed is 10 0. Thus, not only have we learnt how to print multiple
variables using a single WriteLine function, but have also become wiser by the fact that, if a
variable is not assigned a value, it obtains a default value of 0.

a.vb
Module zzz
Sub Main
dim b as boolean
dim i as inte$er
dim j as strin$
j "#i"
i 10
b true
System.Console.WriteLine ("&0' &1' &!' &('" % i ) !0 % i * !0 % b % j "#i")
End Sub
End Module

ut!ut
4alse 7rue 7rue 7rue

A data type represents a specifc type of data. In the above example, we have created three
types of variables:
i is of type integer
j is of type string
b is of type Boolean.

A Boolean type can store only one of the two values, true or false.

The variable i of type integer can hold any valid number. It is assigned the value of 10.

The variable j, of type string, must have its value enclosed within double inverted commas.
It is assigned a value of "hi".

The boolean variable b is initialized to a value of true.

In the WriteLine function following the string, we frst display the expression i > 20, instead
of the variables. Doing so, indirectly poses the question "Is the variable i greater than 20?"
The result can either be true or false. Since the value of the variable i is 10, which is less
than 20, the value of False is displayed. The second expression determines whether the
value of i is less than 20 or otherwise. Since this is afrmative, the value of True is
displayed on the screen.
244258241.doc 1! od 272

The third parameter to the WriteLine function simply displays the value of the boolean
variable b. The value of the boolean variable is not altered from what it was initialized to.
Hence, the output is displayed as True.

The last check performed is, whether the value of the string j is equal to the string value "hi"
or not. Since they both are the same, the resultant value of True is displayed. Thus, all the
above expressions result in a boolean value of either true or false.

a.vb
Module zzz
Sub Main
dim i as inte$er
i 10
i+ i ) ,0 t#en
System.Console.WriteLine ("Condition -rue")
End i+
i+ i ) , t#en
System.Console.WriteLine ("Se.ond Condition -rue")
End i+
End Sub
End Module

ut!ut
Second Condition 7rue

The programs that we have presented so far are absolutely straightforward, since every line
of code that is entered, gets called sequentially. We desire to execute code based on certain
circumstances.

The above program is the perfect prescription for this. We have created an integer i with a
value of 10. Then, we encounter an 'if' statement.

An 'if' statement is always followed by a condition or an expression, and the line ends with a
'then'. In the frst case, a check is performed to determine whether the value of the variable i
is larger than 50 or not. Since the answer is False, all the lines of code leading up to the
'End If', are ignored. Thus, the frst WriteLine function with the Condition True, does not get
executed at all.

The condition with the second 'if' statement, verifes whether the value of i is greater than 5
or not. Since it is, all the code between the 'if' and the 'end if' is executed. Thus, an 'if'
statement is used to make decisions, i.e. to intelligently execute specifc code, depending
upon whether some variables have certain values or not. In this manner, we can efortlessly
write intelligent and dynamic programs.

a.vb
Module zzz
Sub Main
dim i as inte$er
i 10
i+ i ) ,0 t#en
System.Console.WriteLine ("Condition -rue")
else
System.Console.WriteLine ("Condition /alse")
End i+
244258241.doc 17 od 272
i+ i ) , t#en
System.Console.WriteLine ("Se.ond Condition -rue")
End i+
End Sub
End Module

ut!ut
Condition 4alse
Second Condition 7rue

In the above program, the 'if' statement now has the 'else' clause added to it. In the earlier
program, when the result of the 'if' statement was false, no code was executed.
Now, since the 'else' clause has been added, whenever the 'if' statement is false, the
statements within the 'else' block are executed. So, all code from the 'else' upto the 'end if',
is executed. When the 'if' condition results in True, the statements contained within the 'if'
upto the 'else', are executed.

The advantage of using the 'else' clause is that, some code fnally gets executed. However,
the 'else' clause is optional.

Subroutines

a.vb
Module zzz
Sub Main
ab.
End Sub
End Module

$rror
c:\il\a.vb%3& : error BC304'#: (a)e 'abc' is not declared.

By introducing the name abc, we have attempted to call a subroutine or a function by that
name. Like before, an error is generated, since abc has not been declared. Thus, as in the
case of variables, we have to declare or create the subroutine or function before calling our
own code.

a.vb
Module zzz
Sub Main
ab.
End Sub
sub ab.
System.Console.WriteLine("in ab.")
end sub
End Module

ut!ut
in abc

At the very outset, we had created a subroutine called Main, by using Sub. Harnessing the
same mechanism, we now create another subroutine called abc.

244258241.doc 18 od 272
The only diference between the two sub-routines is that the code in Sub Main is called
when the .exe fle is executed, whereas, the code in the other subroutines has to be called
explicitly.

To execute code in a subroutine, just the name of the subroutine has to be specifed on a
blank line. Hence, we have merely specifed the name abc. This action calls the code in the
subroutine, thereby resulting in the WriteLine function being called, with the string 'in abc'.
This sounds too easy to be true!

a.vb
Module zzz
Sub Main
ab.
01r
End Sub
sub ab.
System.Console.WriteLine("in ab.")
01r()
01r
end sub
sub 01r
System.Console.WriteLine("in 01r")
end sub
End Module

ut!ut
in abc
in !<r
in !<r
in !<r

We can create as many subroutines or subs as we like in a single module. The above
program displays two subroutines, both of which are called from the Main block.
Furthermore, the pqr subroutine is called twice from the abc subroutine.
Thus, we enjoy the privilege of calling code contained in any other subroutines, as many
times as we desire. You would notice that at one stage we had called the pqr subroutine,
using the open and close brackets. The brackets are optional. So, their presence or the lack
of it, does not interfere much with the execution of the code.

a.vb
Module zzz
Sub Main
ab.("Hi")
End Sub
sub ab.()
System.Console.WriteLine("#ell")
end sub
End Module

c:\il\a.vb%3& : error BC300'=: 7oo )an+ ar1u)ents to '8ublic Sub abc%&'.

In the above example, an error is generated, since we are passing the string parameter "Hi"
to the sub abc; whereas, the sub abc has not been declared to accept any parameters. So,
let us rectify this situation in the subsequent example.

a.vb
244258241.doc 1" od 272
Module zzz
Sub Main
ab.("Hi")
End Sub
sub ab.(s as strin$)
System.Console.WriteLine(s)
end sub
End Module

ut!ut
"i

The above example demonstrates the correct way of creating a subroutine. The string "hi" is
passed as the value for the variable 's' in the sub abc. The variable 's' is termed as a
parameter. It is supplied to the WriteLine function for display purposes. Subroutines that
accept parameters are very practical and efcacious, since they infuse a lot of fexibility and
generality into the program.

a.vb
Module zzz
Sub Main
2im s%t%u as strin$
s "#i"
t "bye"
u "3o"
ab.(s%t%u)
System.Console.WriteLine("&0' &1' &!'"%s%t%u)
End Sub
sub ab.(s0 as strin$ % byval s1 as strin$% byre+ t1 as strin$)
System.Console.WriteLine("&0' &1' &!'"%s0%s1%t1)
s0 "$ood"
s1 "bad"
t1 "u$ly"
end sub
End Module

ut!ut
.i b+e (o
.i b+e u1l+

In the above example, there are three string variables viz. s, t and u. They are initialized to
"Hi", "Bye" and "No", respectively. These three variables are then furnished as parameters to
the subroutine abc.

In the Sub, the values passed by the three variables, are stored in the parameters s0, s1
and t1. We will explore the other parameter details in a short while.

Thereafter, the three values are displayed using the WriteLine function. Then, the values of
the parameters s0, s1 and t1 are modifed to some other values. Once the subroutine abc
ends, the control moves on to the next line in the Main block.

Here, we again use the WriteLine function to display the values of the variables s, t and u.
To our utter astonishment, we discover that the value of the variable 'u' is diferent from
what it had been initialized to. It displays the new value that has been assigned to it in the
abc subroutine. However, s and t retain their old values.

244258241.doc 2# od 272
In sub abc, we have changed the values of the parameters, and not the original variables.
Notwithstanding this, the value contained in the variable 'u' within the main subroutine,
changes. This is because of the fact that, we have afxed the word 'byref' before the name of
the parameter. This word signifes that if the parameter t1 changes in the sub abc, the
original variable in the calling Sub would also change correspondingly.

By using the word 'byval', any changes made to the value of the variable in the subroutine,
would not percolate down to the original variable.

The default is 'byval', and since it has not been mentioned for the frst parameter, the efect
is that of byval. Thus, it is the sub that decides on whether to refect the changes made,
onto the original variable that is passed as a parameter.

a.vb
Module zzz
Sub Main
2im s as strin$
s "#i"
ab.()
End Sub
sub ab.()
s "3o"
end sub
End Module

$rror
c:\il\a.vb%>& : error BC304'#: (a)e 's' is not declared.

We did not enlighten you earlier about a very essential feature of Sub. However, this seems
to be an opportune time to divulge the fact that, a Sub is an independent and a self-
contained entity. The variable 's' created in the sub main, is not discernible in the sub abc.
Hence, the compiler generates the above error.

a.vb
Module zzz
Sub Main
2im s as inte$er
s ab.(10%!0)
System.Console.WriteLine(s)
End Sub
/un.tion ab.(i as inte$er % j as inte$er) as inte$er
ab. i " j
end /un.tion
End Module

ut!ut
30

Your reaction to this book could range from being extremely positive to being outright
negative and unimpressed. This would depend upon how well you relate to our style. It has
always been our endeavour to explain only a single concept at a time. This could get
exasperating for a large number of people.

The above example highlights the diference between a sub and a function. They are almost
identical, but for one variation, i.e. a function can return a value, whereas, a Sub cannot.
244258241.doc 21 od 272

In many situations, returning values is very important because functions normally perform
certain tasks and return the result of their operation. The above function abc accepts two
integers parameters and returns their sum.

Creating functions is a child's play, since it entails replacement of the word 'Sub' with the
word 'Function' and the words 'End Sub' with the words 'End Function'. The words 'as
Integer' signify that the function will return an integer when it is called. To return a value in
a function, the name of the function has to be initialized to the specifc value. Thus, writing
abc=100 will return 100.
In our case, we are adding up the two parameters 10 and 20, and initializing the function
name abc with the sum of 30. Thus, the variable s in the sub main will now have a value of
30, which is the return value of the Function.

a.vb
Module zzz
Sub Main
2im s as inte$er
s ab.(10%!0)
ab.(100%(00)
System.Console.WriteLine(s)
End Sub
/un.tion ab.(i as inte$er % j as inte$er) as inte$er
ab. (00
ab. i " j
end /un.tion
End Module

ut!ut
30

You may set the return value as many times as you like. No one would whine. The last value
to be returned will be the one that is fnally used. Thus, the return value of 300 is
overridden by the last value to be returned, i.e. 30.

Even though it is the job of a function to return a value, we can avoid storing the return
value in a variable. Thus, in the second round, when the function abc is called, we do not
save its return value in a variable. However, nobody makes a fuss about it.

As has been oft repeated by us, VisualBasic.Netis a very forgiving and fexible language, and
that is precisely why we love it as much as we do!

2. Classes

Visual Basic has never been considered to be a clean programming language. This became a
Gordian knot for Microsoft and began brewing trouble. However, in spite of this setback,
amazingly, no other product has sold more copies than Visual Basic in the history of the
computing world. Thus, Microsoft has no choice but to retain the heart and soul of Visual
Basic, and simultaneously, embellish it with the latest features available in language
technology. This forms the genesis of Visual Basic.Net. Visual Basic .Net is primarily an
extension of the Visual Basic programming language that is shipped with the Visual Basic
product.

244258241.doc 22 od 272
In Visual Basic.Net, which is the improved version of Visual Basic, we can replace the word
'module' with the word 'Class'. Together with this modifcation, one more change is required,
i.e. the word 'Shared' has to be added to the Sub Main. If the main subroutine is not
amended to 'shared', the following error crops up:

$rror
vbc : error BC30=3=: (o accessible 'Main' )et.od wit. an a!!ro!riate si1nature
was found in 'a'.

a.vb
Class zzz
S#ared Sub Main
System.Console.WriteLine("#i")
End Sub
End Class

ut!ut
.i

Now, when we compile and run the program, the code in Main gets called, displaying the
word "hi". A class is an entity like a module, which carries code and variables.

a.vb
Class zzz
S#ared Sub Main
ab.
End Sub
S#ared sub ab.
System.Console.WriteLine("in ab.")
end sub
End Class

ut!ut
in abc

The above example has a subroutine called abc, with the word 'Shared' added to it. If the
word 'Shared' is omitted, the compiler generates the following error:

$rror
c:\il\a.vb%3& : error BC303?@: Cannot refer to an instance )e)ber of a class fro)
wit.in a s.ared )et.od or s.ared )e)ber initiali;er wit.out an e0!licit instance of
t.e class.

Let us now delve upon what the word 'Shared' signifes.



a.vb
Class zzz
S#ared Sub Main
dim a as zzz
a ne4 zzz
a.ab.
01r
zzz.01r
End Sub
sub ne4()
244258241.doc 23 od 272
System.Console.WriteLine("in ne4")
end sub
sub ab.
System.Console.WriteLine("in ab.")
end sub
s#ared sub 01r
System.Console.WriteLine("in 01r")
end sub
End Class

ut!ut
in new
in abc
in !<r
in !<r

The above program has Main and pqr subroutines marked as 'shared', whereas, the others
remain unmarked.

In Sub Main, we frst need to create a variable named 'a' of type 'zzz'. Here, we are not
actually creating an object or variable 'a' of type zzz, but merely stating that the variable 'a'
looks like the class zzz. This is akin to creating variables of a certain type. Also, we can
safely presume that integer, string and long are all classes. The diference is that the Visual
Basic.Net compiler is aware of the fact that these classes are data types.

zzz is a user-defned datatype, which the compiler is oblivious to. Hence, we need to create
an actual instance or occurrence of this datatype. By using the keyword 'new', an instance
or an object of type zzz is created. The line a = new zzz creates a new object zzz in memory,
and returns a handle that is stored in 'a'. To frame it diferently, 'a' represents a fresh zzz
object in memory.

An object is an instance of a class. Thus, the statement 'DIM i as integer' creates an object i,
which is an instance of class integer. For the basic in-built data types such as string,
boolean and integer, there is no need to explicitly mention 'new', which is otherwise
mandatory for the user-defned types.

In Visual Basic.Net, the keyword 'new' frst allocates memory for all the class contents, and
then, it checks for a sub called 'New'. If the sub 'new' exists, it executes the code present in
it. In most other languages, the sub new() is equivalent to a constructor of a class. After the
subroutine ends, a zzz object is created and stored in 'a'. The object 'a' can then be used to
call the other members in the class.

Initially, the abc procedure is called and then, the sub pqr is called twice:
At the frst instance, without the use of the prefx 'a'.
At the second instance, using the class prefx.

The word 'shared' implies that the function can be called without creating an object. Since
abc is not shared, we have to create an instance of a zzz object, in order to access it. The pqr
sub is marked as 'shared'. Therefore, it does not require an instance of an object to access it.

We normally preface a member with the name of the class, which is the default, if not
specifed expressly. The sub of main also is marked as 'shared'. Therefore, it does not require
an instance of the class zzz before it can be used.

244258241.doc 24 od 272
Prior to venturing further into the concept of Shared, let us anatomize the concept of a
constructor.

a.vb
Class zzz
S#ared Sub Main
dim a as zzz
a ne4 zzz
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0'"% i)
end sub
End Class

$rror
c:\il\a.vb%4& : error BC304'': Ar1u)ent not s!eciBed for !ara)eter 'i' of '8ublic
Sub (ew%i As Inte1er&'.

Earlier, the constructor did not accept any parameters. Thus, we were able to call it without
any parameters. In the above program, we have a constructor that expects one parameter of
type integer. However, in the process of creating an instance of the object zzz, we have not
furnished any parameters to 'new'. This results in an error.

a.vb
Class zzz
S#ared Sub Main
dim a as zzz
a ne4 zzz(10)
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0'"% i)
end sub
End Class

ut!ut
in new #0

We have now redressed the above error by passing a parameter to the 'new' statement. So,
when the constructor gets called, the value received in the parameter i is 10. This value is
displayed on the Console. A constructor can be equipped to accept as many parameters as
we wish to supply it.


a.vb
Class zzz
S#ared Sub Main
dim a as zzz
a ne4 zzz(10)
a.ne4(10)
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0'"% i)
end sub
End Class

$rror
244258241.doc 25 od 272
c:\il\a.vb%'& : error BC302>2: Constructor call is valid onl+ as t.e Brst state)ent in
an instance constructor.

Unlike a subroutine, a new constructor cannot be called explicitly. An error is generated in
the above program, since we are attempting to call a constructor by itself. Thus, a
constructor gets called automatically only when the object is created, and not otherwise.
Further, it cannot be called manually.

a.vb
Class zzz
S#ared Sub Main
dim a%b as zzz
a ne4 zzz(10)
b ne4 zzz()
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0'"% i)
end sub
sub ne4()
System.Console.WriteLine("in ne4 ")
end sub
End Class

ut!ut
in new #0
in new
We can have innumerable constructors or 'new' statements in the program, provided each is
assigned diferent parameters. The above program has two new subroutines, the frst one
accepts a single integer parameter, while the second one does not take any parameters. This
program is perfectly valid.

The concept of using the same function name with diferent parameters is called 'function
overloading' or 'sub overloading'.

Now, we present another example on 'function overloading'.

a.vb
Class zzz
S#ared Sub Main
ab.()
ab.(10)
ab.("#i")
End Sub
s#ared sub ab.(i as inte$er)
System.Console.WriteLine("in ab. &0'"% i)
end sub
s#ared sub ab.()
System.Console.WriteLine("in ab. ")
end sub
s#ared sub ab.(5 as strin$)
System.Console.WriteLine("in ab. &0'"% 5)
end sub
End Class

ut!ut
in abc
in abc #0
244258241.doc 2! od 272
in abc .i

In the above example, we have three subs with the same name 'abc', but each of them has
diferent parameters. Out of the three, two subs have the same number of parameters, but
their data types are distinct.


This is permitted, since the name of a function in Visual Basic.Net does not consist of the
name alone, but is composed of the name and the data type of each parameter. Thus, the
name of the frst sub abc that accepts an integer parameter, could be represented by 'abci',
where i is the data type of the parameter. The last sub could be represented by 'abcs', where
s stands for the string type of the parameter. This naming concept initiates uniqueness in
the function names.

This concept is known as 'name mangling', where the signature of the function depends
upon both, the name of the parameters and their datatypes.

Now, we present yet another example on constructors to make the concept of constructors
crystal clear.

a.vb
Class zzz
S#ared Sub Main
dim a as zzz
a ne4 zzz()
End Sub
End Class

a.vb
Class zzz
S#ared Sub Main
dim a%b as zzz
b ne4 zzz()
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0'"% i)
end sub
End Class

$rror
c:\il\a.vb%4& : error BC304'': Ar1u)ent not s!eciBed for !ara)eter 'i' of '8ublic
Sub (ew%i As Inte1er&'.


Let us comprehend the concept of constructors by examining the above two examples. The
frst example compiles without any errors, despite containing no constructor code.

Visual Basic.Net is not complaining for the reason that, when the program does not contain
any constructors, the complier introduces one of its own, as follows:

Sub ne4
End sub

Thus, when a constructor is not created explicitly, the compiler creates one for us. This
constructor does not accept any parameters, nor does it do anything. However, if we include
244258241.doc 27 od 272
even a single constructor, this complimentary constructor is carted-of or taken away. Thus,
in any situation, there would always be at least one constructor present in the code.

In the second example, a constructor with one parameter is present. Therefore, the free
constructor with no parameters, which would have otherwise been generated is not present.
So, creating an instance of the zzz object by calling the constructor that accepts no
parameters, generate an error.

To summarize, when no constructors are present in the class, a constructor that does not
accept any parameters, is automatically generated. However, with the insertion of even a
single constructor, the free constructor is not created. In such a situation, each and every
new variant of the constructor has to be added manually.

a.vb
Class zzz
dim i as inte$er
S#ared Sub Main
dim a as zzz
a ne4 zzz
a.i 10
a.ab.
a.01r
End Sub
Sub ab.
System.Console.WriteLine(i)
i !0
End Sub
Sub 01r
System.Console.WriteLine(i)
End Sub
End Class

ut!ut
#0
20

The above example contains an instance variable i. It is referred to as an instance variable
since unlike 'a', it is not created in a sub, but is created outside the subs and within the
class.

The lifetime of an object such as 'a' endures as long as the sub is active; once the sub
concludes executing its code, all the variables that have been declared in it, lose their values
or are considered non-existent thereafter. The visibility of such variables is restricted to the
function or sub that they are created in. Thus, the object 'a' is visible only within the sub
Main and not in the other subs, such as abc.

On the other hand, the lifetime of the variable i is linked to the life-span of the program.
Since it is declared outside all the subs, it is visible in all the subs within the class.

In main, the value of i is set to 10. It is prefaced with the name of the object, since it is not
shared. Then, the sub abc is summoned, which displays the value of 10 and changes it to
20. Next, when the subroutine pqr is called, the value of the instance variable is 20. This is
for the reason that, only a single copy of i is created in memory, when the zzz object is
created. Thus, both the subs, viz. abc and pqr refer to this same instance variable i.

244258241.doc 28 od 272
a.vb
Class zzz
dim j as inte$er
s#ared dim 5 as inte$er
S#ared Sub Main
dim a%b as zzz
a ne4 zzz(10)
a.ab.(100)
b ne4 zzz(!0)
b.ab.(!00)
End Sub
sub ne4(i as inte$er)
System.Console.WriteLine("in ne4 &0' &1' &!'"% i % j % 5)
j i
5 i
System.Console.WriteLine("in ne4 &0' &1' &!'"% i % j % 5)
end sub
sub ab.(0 as inte$er)
System.Console.WriteLine("in ab. &0' &1'"% j % 5)
5 0
j 0
end sub
End Class

ut!ut
in new #0 0 0
in new #0 #0 #0
in abc #0 #0
in new 20 0 #00
in new 20 20 20
in abc 20 20

The above example reinforces the dissimilarities between a shared variable and a non-
shared variable. The words 'variable' and 'object' may be used interchangeably. In the
manner akin, what is pertinent to a sub is also applicable to a function, unless otherwise
specifed.

In the above program, the class zzz has two variables:
j - which is an instance variable.
k - which is a shared variable.



The basic distinction between the two is as follows:
(a) A shared variable belongs to a class, which implies that each time a new instance of
the class is created, the shared variable does not get re-created. To access the shared
variable, the name of the class is used, since there is only a single shared variable per
class.

(b) An instance variable gets created, each time that a new instance of a class is created.
Therefore, if an object is instantiated on 20 counts, it will result in the creation of 20
new copies of the instance variable in memory.

In Main, two local variables a and b, of type zzz are created. Since they are local, they have a
very short life span. While creating the object 'a', the constructor for the object zzz is
assigned a value of 10. Therefore, in the constructor, the value of i becomes 10, whereas,
244258241.doc 2" od 272
both j and k have a value of 0. If the instance variables are not explicitly initialised, the
system initialises them to a value of zero.

The constructor assigns the value contained in i, i.e. 10, to both the variables j and k.
Therefore, in the second round, the WriteLine function displays the values of all three
variables as 10. The sub abc is then called with a parameter of 100. Here, the values of
variables j and k remain 10, as has been displayed by the WriteLine function. We now re-
initialize both the variables j and k to 100, and then, quit out of the sub.

The next statement in the Main function creates a new instance of zzz, wherein the
constructor is assigned a value of 20. The WriteLine function prints the values of i, j and k
as 20, 0 and 100, respectively. The instance variable j has a value of 0, as it has been freshly
created. Shared variables are not afected by the 'new' keyword. Thus, the variable k retains
its original value of 100, which was set in the abc function. The second WriteLine function
in the constructor displays the newly assigned value of j and k, i.e. 20.

The abc function is called once again using the object b. The variable j now displays the
value of 20, since the constructor of the 'b' object in zzz had initialized it to 20. This variable
is then assigned a value of 200. However, the second copy of j, which belongs to the object
'b', retains its value of 20, since it has nothing to do with the variable j from the object 'a'.

To summarize what we have been harping on over and over, an instance variable belongs to
an object, whereas, a shared variable belongs to a class. This is indubitably evident from the
manner in which these variables are accessed. We are taking the trouble of explaining all
the above code and concepts, in order that you can discern even the most diminutive of the
Visual Basic .Net programs, generated by Visual Studio.Net.

The approach that we have pursued is that we frst explain the concepts using the Visual
Basic.Net compiler, and then we implement them in Visual Studio .Net.

Namespaces

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
a.ab.
End Sub
End Class
Class yyy
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass

ut!ut
abc

The above example lucidly establishes that a Visual Basic.Net program can contain
innumerable classes, as long as one of these classes contains the Sub of Main. The above
program has two classes named zzz and yyy. In the class zzz, 'a' is declared to be an object
of type yyy. After having created the object, the function abc is called from it.
244258241.doc 3# od 272
You may wonder as to what is the big deal here, since the program runs in a manner akin to
any other program. Although we accede to the fact that the program is no diferent from the
earlier ones, nonetheless, we would still like to forge ahead with it.

The class Console has a shared function called WriteLine, which is used to display strings.
So, nothing holds us back from creating a class called Console, in the fashion similar to the
one used to create the class yyy. Then, in the class, we can create our own function named
WriteLine.

This is perfectly within the realms of possibility, since we now know how to create a class
and a function within the class. However, there is bound to be some confusion because
when the user enters the statement 'Console.WriteLine', the framework would be in a
dilemma whether to call the function created by us or the one supplied by Microsoft.

Microsoft seems to have already foreseen this predicament, and therefore, to avert such
name clashes from occurring, the big guys or Visual Basic.Net ordains that every class
should be a part of a name or a namespace. The next example demonstrates the
implementation of namespaces.

a.vb
Class zzz
S#ared Sub Main
dim a as nnn.yyy
a ne4 nnn.yyy
a.ab.
End Sub
End Class
3ames0a.e nnn
Class yyy
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass
End 3ames0a.e

ut!ut
abc

We have efected a minor amendment to the class yyy. A new word, i.e. Namespace has been
introduced above the class yyy, and the name assigned to it is 'nnn'. As a rule, everything in
Visual Basic.Net must terminate with the word End. Therefore, the Namespace also ends
with the words 'End Namespace'.

With the introduction of a namespace, the name of the class is no longer just yyy, but is now
'nnn.yyy'. The syntax for the class name now changes to the following:
name of the namespace followed by a dot, and fnally, followed by the class name.

Thus, whenever we need to refer to the class yyy, the reference to be employed is nnn.yyy. If
we omit the namespace 'nnn' from the DIM statement, the following error is generated:

$rror
c:\il\a.vb%3& : error BC30002: 7+!e '+++' is not deBned.

a.vb
Class zzz
244258241.doc 31 od 272
S#ared Sub Main
dim a as aaa.nnn.yyy
a ne4 aaa.nnn.yyy
a.ab.
End Sub
End Class
3ames0a.e aaa
3ames0a.e nnn
Class yyy
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass
End 3ames0a.e
End 3ames0a.e

ut!ut
abc

In the above example, two namespaces have been added to the class yyy, viz. aaa and nnn.
Thus, the name of the class now becomes aaa.nnn.yyy. The namespace statement can be re-
written as 'Namespace aaa.nnn'.

a.vb
Class zzz
S#ared Sub Main
aaa.nnn.yyy.ab.
End Sub
End Class
3ames0a.e aaa.nnn
Class yyy
s#ared sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass
End 3ames0a.e

ut!ut
abc

In this example, the abc function is marked as 'shared'. Here, no object of type yyy has been
created. Thus, to call the abc function, the name of the class 'yyy.abc' is used. Now, with the
inclusion of the namespace tag above the class, the only way to call this function is by using
its full name, i.e. aaa.nnn.yyy.abc.

This syntax bears a resemblance to the commonly used System.Console.WriteLine. Thus, a
sub or a function has to be read from right to left as follows:
The rightmost entity 'WriteLine' or 'abc' is the name of the method.
The next entry on the left, i.e. 'Console' or 'yyy' is the name of the class.
The next entry on the left, i.e. 'System' or 'nnn' is the name of the namespace entity.
The Console class belongs to the System namespace. The WriteLine function is a shared
function in this class. In the case of methods that are not 'shared', the object name has to
be expressly specifed to access the method.

Namespaces infuence only the class names and not the object names. By employing
namespaces, both similar as well as disparate classes can be placed under a single heading.
244258241.doc 32 od 272
Microsoft has politely reserved the use of the 'System' namespace. Thus, no developer can
ever create a namespace by that name, thereby avoiding any clashes with Microsoft's set of
entities.

Classes sharing the same names can be placed under diferent namespaces without any
confusion. However, the problem with using these namespaces is that they are extremely
lengthy. The next program provides a solution to this poser.

a.vb
6m0orts aaa.nnn
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
a.ab.
End Sub
End Class
3ames0a.e aaa.nnn
Class yyy
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass
End 3ames0a.e

ut!ut
abc

The program begins with the newly introduced keyword of 'Imports', followed by the name of
the namespace, i.e. aaa.nnn. This statement does not introduce any new code, as its sole
task is to add the namespace aaa.nnn to every class, thereby circumventing errors.

For instance, the Visual Basic.Net compiler would have thrown an error on encountering the
class yyy in the DIM statement, since there is no class called yyy. However, on catching sight
of the 'import' keyword, it adds the namespace to the name of the class, resulting in the
name aaa.nnn.yyy. As there already exists a class by this name, the Visual Basic.Net
compiler does not protest.

In case the error still persists, it takes the next set of Imports statement, and attempts to
seek a match. Only when all the Imports fail to fnd a match, a "not found class" error is
thrown. Efectively, the imports statement is like a short form, which when introduced,
eliminates the need for mentioning the namespace on every occurrence of the class.

Bear in mind that it is the namespace, and not the name of the class, which is permitted
after the Imports keyword.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
a.ab.
a.01r
End Sub
End Class
Class yyy
244258241.doc 33 od 272
sub ab.
System.Console.WriteLine("yyy ab.")
end sub
end .lass
Class 777
sub 01r
System.Console.WriteLine("777 01r")
end sub
end .lass


$rror
c:\il\a.vb%?& : error BC304'?: '!<r' is not a )e)ber of '+++'.

The above example has three classes, viz. xxx, yyy and zzz. The class xxx has the sub pqr,
the class yyy has the sub abc, while the class zzz has the sub Main.

In Main, an object 'a' is created to be an instance of the class yyy. Thus, the sub abc can
now be called of it. However, calling the sub pqr using the object 'a' results in an error, as
the class yyy does not contain pqr. The class xxx contains the sub of pqr. Thus, a class is a
self-contained unit wherein, the entities belonging to one class cannot be accessed by
another class.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
a.ab.
a.01r
End Sub
End Class
Class yyy
6n#erits 777
sub ab.
System.Console.WriteLine("yyy ab.")
end sub
end .lass
Class 777
sub 01r
System.Console.WriteLine("777 01r")
end sub
end .lass

ut!ut
+++ abc
000 !<r


In the above program, we have merely added the word 'Inherits' to the name of a class xxx,
on the line below the class yyy. With this new induction, all the entities present in the class
xxx, now belong to the class yyy too. Thus, all the code and instance variables that are
present in the class xxx, can now be used by the yyy object 'a'.

This is one of the most salient concepts in the world of object oriented programming,
wherein, a class such as yyy can derive itself from a base class like xxx. And by virtue of
244258241.doc 34 od 272
this, it can reuse code that is present in this base class. Programmers are very often
mentally fne-tuned to write code in this fashion.

The code is never to be written from a scratch. Instead, it is derived from a class that
already has code present in it. By using 'inherits', the derived class simply inherits
everything from the base class.

Now, insert the following two lines on a single line as in.

Class yyy
6n#erits 777
to
Class yyy 6n#erits 777

This action generates the following error:

$rror
c:\il\a.vb%@& : error BC3020': $nd of state)ent e0!ected.

Even though Visual Basic.Net is known to be an exceedingly fexible language, it still
requires us to adhere to certain rules. Thus, we have no choice but to place the word
'Inherits' on a separate line. The indentation is for the sake of neatness, and for good luck of
course!

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
End Sub
End Class
Class yyy
6n#erits 777
sub ne4
System.Console.WriteLine("ne4 yyy")
end sub
end .lass
Class 777
sub ne4
System.Console.WriteLine("ne4 777")
end sub
end .lass

ut!ut
new 000
new +++

In the above example, the class yyy derives from the base class xxx. Therefore, when an
instance of class yyy is created, two constructors are called, one from the class xxx, and the
other from the class yyy, in the prescribed sequence. This occurs because the class yyy is
also made up of the class xxx. Thus, while an instance of a yyy object is being created, two
objects are created in memory: a xxx object, followed by a yyy object.

During the creation of these two objects in memory, the constructors of these classes get
called. A constructor, as you may recall, is called when an object is created. The constructor
244258241.doc 35 od 272
of the base class, i.e. xxx is always called frst, followed by the constructor of the derived
class yyy.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
End Sub
End Class
Class yyy
6n#erits 777
sub ne4
mybase.3e4
System.Console.WriteLine("ne4 yyy")
end sub
end .lass
Class 777
sub ne4
System.Console.WriteLine("ne4 777")
end sub
end .lass

ut!ut
new 000
new +++

Yet another line has been added to the constructor of the class yyy, i.e. mybase.New. Despite
our not having created any variable or object called mybase, no error is generated. This is
because, every method or function or sub is provided with a free object called mybase,
which is a handle to the base class.

By specifying mybase.New, the constructor of the base class gets called. No specifc reason
can be attributed to this, but most code written in the Visual Basic.Net world, calls the
constructor of the base class in the above-mentioned manner. The mybase object is used to
access members of the base class.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
End Sub
End Class
Class yyy
dim i as inte$er
sub ne4
Me.i 10
System.Console.WriteLine("ne4 yyy &0'" % Me.i)
end sub
end .lass

ut!ut
new +++ #0

Obtaining a free ride in life has never been too easy. In the Visual Basic.Net world, not only
do we get a free mybase object, but also acquire another object called Me. The Me object is
244258241.doc 3! od 272
used to refer to itself, while the mybase object is used to refer to the base class. In the above
example, whether we write Me.i or i, it would mean the same thing.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy(100)
a.ab.
End Sub
End Class
Class yyy
dim i as inte$er 10
sub ne4(i as inte$er)
System.Console.WriteLine("ne4 yyy &0' &1'" % Me.i % i)
Me.i i
end sub
sub ab.
System.Console.WriteLine("ne4 yyy &0' &1'" % Me.i % i)
end sub
end .lass

ut!ut
new +++ #0 #00
new +++ #00 #00

The utility of the reserved word Me is evident in the above example, where the class yyy has
an instance variable named i, and the parameter to the constructor is also named i.

In the class zzz, 'a' is created as an object to yyy, by assigning a value of 100 to the
constructor. Doing so would load the yyy object in memory, where the frst line is a DIM
statement. The DIM statement utilizes an 'equal to' sign to initialize the variable during its
creation. Thus, the instance variable i is initialized to the value of 10.

Thereafter, the constructor of class yyy is called, where the WriteLine function displays the
value of i. The i being referred to here is the parameter i in the constructor, and not the
instance variable i. This is because the parameters and local variables get higher preference
in a function.

However, using Me.i in the constructor would refer to the instance variable and not to the
parameter. The statement Me.i = i, would initialize the instance variable i to the value stored
in the parameter i. In the sub abc, i and Me.i will always refer to the instance variable, since
there is no parameter named i.

Thus, the keyword Me proves to be of great utility, when there is an instance variable and a
local variable, both having the same name.

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
End Sub
End Class
Class yyy
6n#erits 777
244258241.doc 37 od 272
sub ne4
mybase.3e4
System.Console.WriteLine("ne4 yyy")
end sub
end .lass
Class 777
6n#erits 000
sub ne4
System.Console.WriteLine("ne4 777")
end sub
end .lass
Class 000
sub ne4
System.Console.WriteLine("ne4 000")
end sub
end .lass

ut!ut
new !!!
new 000
new +++

In the above program, the class ppp is a self-contained unit, which is not derived from any
other class. Then, the class xxx is derived from class ppp. Hold your horses! There is more
to it. One more class yyy is then derived from the class xxx. As a result, the class yyy is
directly/indirectly derived from the two classes xxx and ppp.

Now, creating an instance of class yyy, would lead to the creation of three objects in memory,
viz. xxx, yyy and ppp. The sequence is important, since the base class constructor always
gets called frst.

Thus, the ppp constructor gets called frst, the xxx class gets called next, and fnally, it is
the yyy class that gets called. The abovementioned rules apply, irrespective of the number of
classes that we derive from.
3. ,in4or)s

The Visual Basic.Net compiler has a large number of options, one of which is the /target
option, which determines how the output should appear. Under Windows, a dll fle and an
exe are both similar. The only apparent distinction between the two is that an exe fle can be
executed at the command prompt, whereas, a dll cannot. It acts as a carrier or a reservoir of
code. By default, the target output is set to exe. Now, create the following fle called b.vb:

b.vb
0ubli. .lass yyy
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass

The fle b.vb is composed into a dll fle, instead of an exe fle. To achieve this, the following
command is used:

>vbc Ctar1et:librar+ b.vb

244258241.doc 38 od 272
The above command creates a fle called b.dll, which carries the code of the class yyy,
containing a sub called abc. The word 'public' mentioned before the name of the class
signifes that the entire world has access to the code in the class. Words such as 'public' are
called access modifers, which we shall address in a subsequent section. If we eliminate the
'public' access modifer, the next program would not work successfully.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy
a ne4 yyy
a.ab.
End Sub
End Class

>vbc a.vb Cr:b.dll

ut!ut
abc

One of the most vital advantages of writing code is that the other programmers too can
access it. For example, the fle b.dll carries a class yyy, which can contain numerous
functions like abc. Now, any other program can also refer to this code.

On running the Visual Basic.Net compiler at this stage, an error will be reported, since the
compiler is unaware of the identity of the fle that contains the code. Thus, we need to
explicitly inform the compiler about the identity of the dll fle that contains the function.

This is achieved by specifying the command line option /R, where the R stands for
'reference'. It is followed by the name of the dll that contains the code. Microsoft also ofers
its own set of classes by locating them in multiple dll fles. Hence, to access the code
contained in them, we need to use the /R option at the compiler level.

This chapter is primarily focused on building GUI applications. In the Visual Basic.Net
program stipulated below, the class zzz is derived from the class Form. This implies that all
the code in the class Form is now made available in the class zzz.

a.vb
6m0orts System.Windo4s./orms
8ubli. Class zzz
6n#erits /orm
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
End Class

>vbc a.vb Cr:S+ste).,indows.4or)s.dll Cr:S+ste).dll

244258241.doc 3" od 272
Sceen 3.1

On running the above program, general happiness prevails, since a pretty little window
comes into view, as shown in screen 3.1.

Since the class zzz is derived from the Form class, all methods and instance variables within
the Form class, are now made available in zzz. This establishes the potency and beauty of
the concept of inheritance.

The Form class belongs to the namespace of System.Windows.Forms. This explains the
presence of the 'imports' statement, which is provided with the primary aim of evading the
use of the entire namespace before Form, since the class is used very often.

All classes in the .Net world must belong to a namespace. If we do not specify a namespace
for a class, it will get placed in the global namespace.

In the Main function, frst an object of type zzz is created. It is then passed as a parameter
to the Run function. Abiding by what we have learnt so far, we can safely conclude that
Application is the name of the class, and Run is a shared function. The Application class
also falls under the namespace of System.Windows.Forms.

The fnal action to be taken is to furnish the Visual Basic.Net compiler with a reference to
the dll, which contains the code of the Forms and Application classes. The help text on the
above-mentioned classes clearly reveals that the dll that constitutes the
System.Windows.Namespace, is the System.Windows.Forms dll. This name is passed on to
the Visual Basic.Net compiler using the /R option.

The Run function merely requires an object derived from Form. Once it gets the custody of
this object, it displays a cool looking window. Never mind how or why!

a.vb
Class zzz
S#ared Sub Main
dim a as yyy
a ne4 yyy
a.i 10
a.ab.
a.01r
End Sub
End Class
Class yyy
6n#erits 777
sub ab.
System.Console.WriteLine("yyy ab. &0'" % i)
i (0
244258241.doc 4# od 272
end sub
end .lass
Class 777
0ubli. dim i as inte$er
sub 01r
System.Console.WriteLine("777 01r &0'"% i)
end sub
end .lass

ut!ut
+++ abc #0
000 !<r 30

The above program demonstrates a simple concept. The class xxx has a public instance
variable i. Thus, other classes can now access this variable. The class yyy is derived from
the xxx class, with 'a' as its object. Now, 'a' is allowed access to the variable i.

The golden rule here is that, whatever an object of class xxx is allowed to do with the
members of the class xxx, the same leeway is granted to an object of the class derived from
xxx. Furthermore, there is only one copy of the variable i. So, any changes made to it from
the sub abc, would be refected in the sub pqr within the class xxx.

The next program converges around this concept.

a.vb
6m0orts System.Windo4s./orms
8ubli. Class zzz
6n#erits /orm
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
sub ne4
my;ase.3e4
Me.-e7t "<ijay Mu5#i"
end sub
End Class

Sceen 3.2

The above program displays a window, as seen in screen 3.2, where the title of the window is
given as "Vijay Mukhi".

The program has a constructor 'new', which traditionally calls the original constructor. This
is not mandatory, but we would rather follow the rules laid down by the Big Daddy! Then,
using the keyword 'Me', the variable Text is initialised to "Vijay Mukhi". The Text member is
244258241.doc 41 od 272
not created anywhere in the class. So, it is safe for us to assume that it exists in the class
Form.

This initialisation results in a change in the title of the window. The Run function
determines the title of the window, after ascertaining the contents of the Text variable. The
default is a blank value. We are still at the preliminary stage of customizing the Windows
Forms.

a.vb
6m0orts System.Windo4s./orms
6m0orts System.2ra4in$
8ubli. Class zzz
6n#erits /orm
2im b as ;utton
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
sub ne4
my;ase.3e4
Me.-e7t "<ijay Mu5#i"
b ne4 ;utton
b.-e7t " sonal"
dim 0 as 8oint
0 ne4 8oint(10%100)
b.Lo.ation 0
2im . as Control.ControlColle.tion
. Controls
..9dd(b)
end sub
End Class

>vbc a.vb Cr:S+ste).,indows.4or)s.dll Cr:S+ste).dll Cr:S+ste).6rawin1.dll

This example displays a button with the name "sonal" in it, as shown in screen 3.3.

Sceen 3.3

We initiate the above example by creating an object 'b', whose type is Button, and which
resides in the System.Windows.Forms namespace.

The class contains code and instance variables that are conversant with the role of a
button.When the Text property of the Button object 'b' is set to some text such as "sonal",
this text gets displayed on the Button.

244258241.doc 42 od 272
Now, to place the button at a specifc position on our screen, the Point class is used, whose
two members represent a Point on the graphics screen. These two members x and y are
initialised to the values 10 and 100, respectively, through the Point constructor. The Point
class is in the System.Drawing namespace. Therefore, during compilation, the reference
of /r is set to the fle System.Drawing.dll.

The Location property of the Button object is then initialised to this freshly created Point
object p. The most pertinent action at this stage is to inform the Form class that a Control is
being added to the Form.

The Form class has a property called Controls, whose type is Control.ControlCollection. This
property keeps track of all the controls that are placed on the form.

So, by using the Add function in the Control.ControlCollection, we can add the button
control to the Collection object, thereby displaying the button on the form. This is how we
add a Button Control to our form.

a.vb
6m0orts System.Windo4s./orms
6m0orts System.2ra4in$
8ubli. Class zzz
6n#erits /orm
2im b%b1 as ;utton
2im t as -e7t;o7
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
sub ne4
my;ase.3e4
Me.-e7t "<ijay Mu5#i"
b ne4 ;utton
b.-e7t "sonal"
dim 0 as 8oint
0 ne4 8oint(10%100)
b.Lo.ation 0
b1 ne4 ;utton
b1.-e7t "<MC6"
0 ne4 8oint(=0%1>0)
b1.Lo.ation 0
2im s as Size
s ne4 Size(,0%?0)
b1.Size s
t ne4 -e7t;o7
t.-e7t "Hi"
0 ne4 8oint(1=0%100)
t.Lo.ation 0
2im . as Control.ControlColle.tion
. Controls
..9dd(b)
..9dd(t)
..9dd(b1)
end sub
End Class

244258241.doc 43 od 272
This example culminates in the creation of a window with two buttons, one larger than the
other and a textbox containing the value "hi". This is shown in screen 3.4

Sceen 3.4

One more button is added to the form in the same manner as before. Thereafter, the new
instance of the button b1 is provided with a Size object. The Size class comprises of the
width and height members, which are to be initialised using the constructor. The Size
property of the Button class determines the size of the control. In case the dimensions are
not mentioned, the default values are taken, as seen in the case of the Button b.

The TextBox class is used to place a TextBox control on the form. Here also, the Text
property determines the contents that are to be displayed with the TextBox. Everything else
remains just the same.

This example illustrates how multiple controls can be placed on a single form. The only
impediment here is that, each time that the Control is to be added to the form, the services
of the Add function have to be exploited. So, if there are 100 controls to be placed on the
form, the Add function will be executed a 100 times! Let us simplify this process by
introducing the concept of Arrays.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a(!) as inte$er
a(0) 1
a(1) 10
a(!) =0
System.Console.WriteLine("&0' &1' &!'"% a(0)% a(1)% a(!))
end sub
End Class

ut!ut
# #0 40

An array is a variable with a single name, but is equipped to hold multiple values. The above
DIM statement of "a(2) as integer" creates three variables named a(0), a(1) and a(2). Thus, in
a single stroke, multiple variables have been created. These variables conduct themselves in
a manner similar to the normal variables. At this stage, the only diference that you need to
take heed of is, that this type of variable has a pair of open-close brackets following it.
a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a(!) as inte$er
dim i as inte$er
i 0
244258241.doc 44 od 272
a(i) 1
i !
a(i) 10
i 1
a(i) 100
System.Console.WriteLine("&0' &1' &!'"% a(0) % a(i) % a(!))
end sub
End Class

ut!ut
# #00 #0

The above example showcases the most valuable facet of an array.

First, we create an array of size 3, followed by an integer variable i, which is initialised to a
value of 0. Earlier, we had specifed a number in round brackets, but here, we specify the
variable i instead. Thus, the line a(i) = 1 will evaluate to a(0) = 1, since the variable i has a
value of 0. On the next line, we change the value of the variable i to 2. Therefore, the
statement a(i) = 10 evaluates to a(2) = 10. The variable a(1) is initialised in a similar manner.

Hence, in the above example, the value of the variable i determines the name of the variable.
To display the value of the array variables, similar rules apply. The use of variables in lieu of
constant numbers assists in making the code more generic.

Loops

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
i 1
2o 4#ile i * ,
System.Console.Write("&0' " % i)
loo0
end sub
End Class

If you run the above program, it would continue to execute till eternity. So, hold on! Let us
appreciate the code frst.

We frst create an integer variable i, and set its value to 1. Then, we come across a 'Do while'
statement containing the condition i <= 5. The 'Do while' statement, including the condition
and the loop, are part and parcel of the looping construct. A loop construct is pressed into
action when the same code needs to be repeated multiple times.

The condition i <= 5 will evaluate the value of i. Since it is 1, the condition evaluates to
1<=5, which is True. Since the condition results in True, all code enclosed within the 'Do
while' and the loop, gets executed. Presently, it contains only a Write function, which is very
similar to the WriteLine function, except for the 'return' at the end. This Write function
displays the value of the variable i.

On encountering the loop statement, the control in code execution loops back to the 'Do
while' statement, where the condition is checked again. Since the value of i is still 1, the
condition results in True, thereby executing the Write Function and the loop.
244258241.doc 45 od 272

The loop again takes the control back to the 'Do While' statement, and the whole process
iterates itself. This action will keep repeating itself till eternity, since the condition after the
'Do While' never becomes False. Thus, we are trapped in an incessant loop. Press Ctrl C to
terminate the loop.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
i 1
2o 4#ile i * ,
System.Console.Write("&0' " % i)
i i " 1
loo0
System.Console.Write("..&0' " % i)
end sub
End Class

ut!ut
# 2 3 4 ' ..?

In this program, only one additional line has been added to the earlier program. This line
enhances the value of the variable i by 1. This amendment results in printing the numbers
from 1 to 5.

This is because, when the value of the variable i is 1, the condition becomes 1<= 5, which
evaluates to True, and the value of i is printed, using the Write function.

Then, the value is incremented by 1, making it 2. The condition that is now checked is 2<=5.
This too results in True and the process is reiterated. However, when the value of i reaches
6, the condition evaluates to 6<=5. The outcome of this is False and the loop terminates.
The control is now passed to the next statement after loop. The value of i that is 6, is now
printed with two dots preceding it. A loop construct is implemented when code has to be
executed repetitively.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
i 1
4#ile i * ,
System.Console.Write("&0' " % i)
i i " 1
End 4#ile
System.Console.Write(".&0' " % i)
end sub
End Class

ut!ut
# 2 3 4 ' .?

The output of the two programs remains almost identical, except that the double dots are
replaced by a single dot. This is a sure indication of why programming languages exasperate
us! In place of the 'Do While' loop, we now have the 'While End While' loop. This amendment
in the syntax however does not translate into any change in the output.
244258241.doc 4! od 272

Thus, it is entirely your decision to use either a 'While End While' or a 'Do While' loop. There
are myriad ways of achieving the same result. However, we would advise you to stick to just
one loop construct under all circumstances.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
i 100
+or i 1 to ,
System.Console.Write("&0' " % i)
ne7t
System.Console.Write(".&0' " % i)
end sub
End Class

ut!ut
# 2 3 4 ' .?

One more variation of the loop construct is the For Next loop. Here, a variable has to be
created, so that it can be used as a counter. We have created an integer variable i and
initialised it to 100. The next line has the 'for' syntax, "for i = 1 to 5".

Despite the variable being initialised to 100, the 'for statement resets its value to 1. Since
the value of i falls within the range of 1 to 5, all the code until the Next statement is
executed.


The 'Next' statement is like the loop statement. It moves the control back to the top of the
'for' loop, but only after incrementing the value of the counter by 1. The code from the 'for'
upto the 'next' is then executed once again. This process is repeated until the value of the
variable i reaches 6. As soon as i falls out of range, the line that immediately succeeds the
'for- next' statement, is executed.

The variable i is not required to be initialised, since the 'for' statement resets its value in any
case.

You are bound to feel perplexed while determining the loop construct to be implemented.
You may adopt our methodology wherein, on Mondays, Wednesdays and Fridays, we use the
'While' construct, and on Tuesdays, Thursdays and Saturdays, we use the 'For' construct.
Sunday being a rest day, we desist from writing any code. ;-)

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
dim b(() as inte$er
+or i 0 to (
b(i) i@10
ne7t
+or i 0 to (
System.Console.Write(".&0' " % b(i))
ne7t
end sub
244258241.doc 47 od 272
End Class

ut!ut
.0 .#0 .20 .30

The above example amply demonstrates how arrays work seamlessly with Loop Constructs.
We create an array 'b' of 4 integers and 1 integer variable named i. In the 'for' statement, i
will have values ranging from 0 to 3.


In the frst round, when the value of the variable i is 0, the name of the variable becomes
b(0) and its value becomes 0*10 = 0. Then, when the value of the variable i becomes 1, the
name of the variable becomes b(1), and its value becomes 1*10 = 10. In this manner, all the
members of the array are initialised to values that are multiplication factors of 10.

The second 'for' loop is used to display the values of all the members of the array. This is
achieved by using the Write function. Thus, arrays and the loop mechanism go hand-in-
glove. The combination has been employed extensively in this book. Its use has also been
witnessed in many of the other programming languages.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
dim b() as inte$er &1%!0%=0 % 100'
+or i 0 to (
System.Console.Write(".&0' " % b(i))
ne7t
end sub
End Class

ut!ut
.# .20 .40 .#00

Short forms may be considered as a bane or a boon. In the above example, we have
demonstrated how arrays can be created and initialised simultaneously.

Using the = sign with DIM, diferent array values can be assigned to the members of the
array, by placing the values in a pair of curly brackets {}. The 'for' loop confrms these values
in the array. We could have easily shirked from explaining this concept, but we thought it
prudent to deal with it, since this concept has been encountered on numerous occasions in
various Visual Basic.Net programs.


Failures are considered to be stepping-stones to success. In the same vein, errors in
programming languages are believed to make a programmer a lot wiser. Therefore, we have
sprinkled this book generously with many of these error messages. Also, in a programming
language, every rule that is not abided by, generates a corresponding error message.

For example, if we change the array initialising line to the following:

dim b(() as inte$er &1%!0%=0 % 100'

the error that is generated is :
244258241.doc 48 od 272

$rror
c:\il\a.vb%4& : error BC30?=2: $0!licit initiali;ation is not !er)itted for arra+s
declared wit. e0!licit bounds.

At the frst glance, you may be astounded by the error message, because so far, we have
merely created an array of 4 variables and initialized each of these array members. However,
programming languages in a sense may be compared to the human behavior, especially
when it comes to being extremely moody and whimsical.

In the Visual Basic.Net language, it is very clearly stated that when an array is initialised at
the time of creation, the size must not be specifed, even though it may be known in
advance. The compiler is of the opinion that we are encroaching on its prerogative of
determining the size of the array. On various occasions, you will realize that a large number
of rules stipulated by the compiler, have become rigid and redundant. Welcome to the real
world !

However, some errors do manage to dodge detection. Thus, even if the program compiles
normally, there is always a possibility of encountering errors on running the program.

Rectify the above error and change the 'for' loop to the following:
+or i 0 to =

By increasing the range from 3 to 4, one more array member can now be accessed. However,
the array extends only from b(0) to b(3).
While the process of scanning the code is on, the compiler is unable to detect such
programming errors. Therefore, it compiles successfully. However, it is during the execution
when the program tries to access b(4); in other words, when it goes beyond the bounds of
the array, the following exception is thrown:

/n.andled $0ce!tion: S+ste).Inde0utfDan1e$0ce!tion: Inde0 was outside t.e
bounds of t.e arra+.

Thus, an exception is an error that the compiler fails to detect. It occurs only at run time.
This is an ample proof of the fact that, you can never be absolutely positive about whether
your program will run error-free or not, despite having compiled successfully.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as aaa
dim b as bbb
a b
end sub
End Class
.lass aaa
end .lass
.lass bbb
end .lass

$rror
c:\il\a.vb%'& : error BC303##: 5alue of t+!e 'bbb' cannot be converted to 'aaa'.

244258241.doc 4" od 272
There are great many people in this world, who are very selective about the people that they
associate themselves with. In all probability, they would have picked up this trait from
programming languages like Visual Basic.Net. ;-)

Both, an 'integer' as well as a 'string', are classes that the Visual Basic.Net complier
understands intrinsically. But, when we create two classes aaa and bbb, they are considered
external entities, since Visual Basic.Net is not clued-up about them. Therefore, the classes
have been created explicitly in the program. Now, when we try to equate one with the other,
we get an error.

The fundamental rule in all modern programming languages is that, we cannot equate two
variables or objects with each other, unless they belong to the same class, or are of the same
data type. Therefore, an object of class aaa cannot be equated to an object of class bbb, even
though the contents of both may be the same.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as aaa
dim b as bbb
a b
end sub
End Class
.lass aaa
end .lass
.lass bbb
in#erits aaa
end .lass

However, there are always a few exceptions to every rule. Two diferent objects can be
equated to each other, provided one derives from the other. Therefore, the only modifcation
that we have introduced in the above program is that, we have derived the class bbb from
the class aaa. The class bbb now comprises of both aaa and bbb.

The amended rule now reads as follows: Two diferent classes can be equated, provided the
class on the right of the 'equal to' sign is a derived class, and the one on the left is the base
class. This is permissible since a derived class contains the base class. This rule applies
wherever a data type is expected, such as, the parameters to a function, etc. The same rule
applies to the members of an array also.



a.vb
8ubli. Class zzz
S#ared Sub Main()
dim b(!) as aaa
b(0) ne4 aaa
b(1) ne4 bbb
b(!) ne4 ...
end sub
End Class
.lass aaa
end .lass
.lass bbb
in#erits aaa
244258241.doc 5# od 272
end .lass
.lass ...
in#erits bbb
end .lass

In this program, three classes are created. The class aaa is an independent entity, which
does not derive from any class. The class bbb derives from the class aaa. Finally, the class
ccc derives from the class bbb.

Thus, the class ccc comprises of classes aaa and bbb, whereas, the class bbb encompasses
the class aaa. Thereafter, an array 'b', of type aaa and size 3, is created.

The member b(0) is initialised to an aaa object. The array member b(1) is set to a bbb type,
and b(2) is equated to a ccc object. None of the above generates an error, since we can
equate a base class to a derived class, bearing the following rule in mind that, the object on
the right should be larger than the one on the left.

a.vb
6m0orts System.Windo4s./orms
6m0orts System.2ra4in$
8ubli. Class zzz
6n#erits /orm
2im b%b1 as ;utton
2im t as -e7t;o7
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
sub ne4
my;ase.3e4
Me.-e7t "<ijay Mu5#i"
b ne4 ;utton
b.-e7t "sonal"
dim 0 as 8oint
0 ne4 8oint(10%100)
b.Lo.ation 0
b1 ne4 ;utton
b1.-e7t "<MC6"
0 ne4 8oint(=0%1>0)
b1.Lo.ation 0
2im s as Size
s ne4 Size(,0%?0)
b1.Size s
t ne4 -e7t;o7
t.-e7t "Hi"
0 ne4 8oint(1=0%100)
t.Lo.ation 0
2im . as Control.ControlColle.tion
. Controls
2im a() as Control &b%b1%t'
..9dd:an$e(a)
end sub
End Class

We took a small detour into certain aspects of the language to simplify the explanation of
the above example. In order to add controls to the form, the Add function from the Controls
244258241.doc 51 od 272
collection, was called multiple times. It is easy to desist from this repetition by using the
AddRange function, which accepts an array of Control objects as a parameter.

So, after creating the individual controls and setting their properties, we then create an
array 'a' of type Control. The array is initialised to the three control objects at the time of
declaration itself. The values assigned are the two Button types b and b1 and the TextBox t.

You should be well apprised of the fact that the array type is Control, and the array
members are of type Button and TextBox. The compiler does not gripe at this approach,
since the Button and TextBox classes are derived from the class Control, thereby making
Control as the base class. Now, when we run the program, the controls get displayed on the
Form Window.

The next step is to activate some code when the button is clicked upon. To implement this,
we again need to take a break away from the regular routines, and fathom out the language
a little further.

Event Handling

a.vb
8ubli. Class zzz
Wit#Events b as yyy
S#ared Sub Main()
dim a as zzz
a ne4 zzz
End Sub
sub ne4
b 3e4 yyy()
b.01r
b.ab.()
end sub
Sub vijay() Handles b.e
System.Console.WriteLine("Hi")
End Sub
End Class
0ubli. .lass yyy
Event e()
Sub ab.()
:aiseEvent e
End Sub
Sub 01r()
System.Console.WriteLine("01r")
End Sub
end .lass

ut!ut
!<r
"i

Let us examine the above program in small parts.

The class yyy has an entity called 'e', which is neither a variable nor an object, but an event.
The 'event' keyword is understood intrinsically by Visual Basic.Net.

244258241.doc 52 od 272
The entity 'b' is of type yyy, but since it has the WithEvents keyword associated with it, the
class will be used solely to handle events. We are fully aware that the concept of events has
not been clarifed so far.

To initialise the event object 'b', the zzz object has to be created, since it is the constructor or
the sub 'new' of zzz, that actually instantiates it. Then, using b, the two functions pqr and
abc are called of the yyy object. At this point in time, the WithEvents keyword does not
prohibit the yyy type from calling the sub pqr and abc.

The WithEvents keyword aids in working with events, but b will always remain a yyy object.
Thus, this keyword augments the existing features of the object.

In the function abc, there is a statement RaiseEvent within which, the name of the event
has been specifed. As always, the round brackets placed after the event name, are optional.

This statement performs a considerable amount of work. It checks for functions in class zzz.
These functions contain the word 'Handles', followed by the object name 'b', and fnally,
followed by the event 'e'. It only looks at functions in zzz, because the function abc has been
called from this class.



The function 'vijay' satisfes both these criteria:
It contains the Handles keyword and the object name 'b'
It also comprises of the name of the event 'e', which is raised by RaiseEvent.

Just about anything can trigger of an event, such as a mouse-click, or a key press on the
keyboard, or the shutting of a window.

Here, the event is set by calling the function abc. The function calls RaiseEvent, which calls
all functions from the class zzz handling this event object combination. There can be
innumerable such functions, which the event in class yyy is simply unaware of.

a.vb
8ubli. Class zzz
Wit#Events b as yyy
S#ared Sub Main()
dim a as zzz
a ne4 zzz
End Sub
sub ne4
b 3e4 yyy()
b.01r
b.ab.()
end sub
Sub vijay() Handles b.e
System.Console.WriteLine("Hi")
End Sub
Sub mu5#i() Handles b.e
System.Console.WriteLine("Hi1")
End Sub
End Class
0ubli. .lass yyy
Event e()
Sub ab.()
244258241.doc 53 od 272
:aiseEvent e
End Sub
Sub 01r()
System.Console.WriteLine("01r")
End Sub
end .lass

ut!ut
!<r
"i#
"i

In the above example, the class zzz has two functions, viz. vijay and mukhi, both of which
can handle the event 'e' using the object 'b'. So, when the event 'e' is raised, both the
functions vijay and mukhi get called one after the other. This proves that when the function
abc is called, some code will get triggered of in the class zzz.

a.vb
8ubli. Class zzz
Wit#Events b as yyy
Wit#Events . as yyy
26M d as yyy
S#ared Sub Main()
dim a as zzz
a ne4 zzz
End Sub
sub ne4
b 3e4 yyy()
b.ab.()
. ne4 yyy
System.Console.WriteLine("3e4 Abje.t")
..ab.
d ne4 yyy
System.Console.WriteLine("3e4 Abje.t1")
d.ab.
end sub
Sub vijay() Handles b.e % ..e
System.Console.WriteLine("vijay")
End Sub
Sub mu5#i() Handles b.e% ..+% b.+% ..e
System.Console.WriteLine("mu5#i")
End Sub
Sub sonal() Handles ..+
System.Console.WriteLine("sonal")
End Sub
End Class
0ubli. .lass yyy
Event e()
Event +
Sub ab.()
:aiseEvent e
System.Console.WriteLine("Event")
:aiseEvent +
End Sub
end .lass

ut!ut
)u:.i
vi*a+
244258241.doc 54 od 272
$vent
)u:.i
(ew b*ect
)u:.i
vi*a+
$vent
sonal
)u:.i
(ew b*ect#
$vent

The above program is mammoth in size. So, let us address it in small parts. We have three
yyy objects named b, c and d. Since the WithEvents clause has been used only for the b and
c objects, the d object cannot be used for event handling. As was done in the earlier
program, we create a new yyy object and call the abc function.

In the abc function, we frst raise the event 'e'. On doing so, the Visual Basic.Net system will
check all the functions that handle the event object b.e. Two functions named vijay and
mukhi, which handle this object event, get called. A point to be noted here is that a sub can
handle as many object event combos as is desired. Then, the Event string is displayed.


Thereafter, another event f is raised. The system now searches all the functions for the
combination of b and f. The only match found is the function mukhi.

Object c is then initialized to new yyy and the Write function displays the string New Object.

Now, function abc is called, using the object c. So, the raise event will check for subs having
a combo object c, and an event e. The subs that correspond to this criterion are Vijay and
Mukhi. And fnally, the last RaiseEvent raises the event f, and calls mukhi and sonal.

The object d also calls the function abc, thereby raising both the events e and f. Nothing
transpires because there are no subs that can handle the object d, due to the absence of the
keyword 'WithEvents'. The class yyy is equipped to contain multiple events, such as 'e' and
'f'. The function abc too can raise multiple events.

a.vb
8ubli. Class zzz
Wit#Events b as yyy
S#ared Sub Main()
dim a as zzz
a ne4 zzz
End Sub
sub ne4
b 3e4 yyy()
b.ab.(100)
end sub
Sub vijay(i as inte$er ) Handles b.e
System.Console.WriteLine("vijay &0'" % i)
End Sub
End Class
0ubli. .lass yyy
Event e(i1 as inte$er)
Sub ab.(j as inte$er)
:aiseEvent e(j)
End Sub
244258241.doc 55 od 272
end .lass
ut!ut
vi*a+ #00

In the above example, the event e is defned to accept an integer parameter. The brackets are
to be provided for the event entity only, when parameters are to be specifed. The name of
the parameter is of no consequence at all.

As an outcome of this modifcation, when the event 'e' is raised, an integer has to be
specifed as the parameter. The event is passed the parameter j, which has been passed from
the constructor to the function abc.

The other amendment that has been initiated is with regard to the sub vijay, which now
requires an integer parameter as part of its signature. The Handles and the WithEvents are
oblivious to the changes that occur when parameters are passed to events.

a.vb
6m0orts System.Windo4s./orms
6m0orts System.2ra4in$
6m0orts System
8ubli. Class zzz
6n#erits /orm
Wit#Events b 9s ;utton
S#ared Sub Main()
dim a as zzz
a ne4 zzz()
900li.ation.:un(a)
End Sub
sub ne4
my;ase.3e4
Me.-e7t "<ijay Mu5#i"
b ne4 ;utton
b.-e7t "sonal"
dim 0 as 8oint
0 ne4 8oint(10%100)
b.Lo.ation 0
2im . as Control.ControlColle.tion
. Controls
2im a() as Control &b'
..9dd:an$e(a)
end sub
Sub vijay(s 9s Abje.t%e 9s Event9r$s) Handles b.Cli.5
Messa$e;o7.S#o4("Hi")
End Sub
End Class

Let us revert back to the Windows Forms application. Now, when we click on the button,
certain code gets called. The button object b has the WithEvents keyword added to it, due to
which, it could now trap events in the Button object.

244258241.doc 5! od 272
Sceen 3.5

Yet another change has been initiated wherein, the sub vijay accepts two parameters. Also,
the keyword 'Handles' has been afxed with the name of the Button object 'b' and with the
Event within the Button object Click. Resultantly, when the button is clicked upon, code
contained within the button class gets called.

The framework checks for an event called Click within the class, and it calls the command
RaiseEvent with two parameters. This RaiseEvent searches in the class zzz for a sub that
has a Handles, alongwith an object event match b.Click. Since the match is found in the sub
vijay, the code in vijay gets executed.


This is how we can ensure that our own code gets called, whenever the Click event occurs.
The MessageBox is shown in screen 3.5.

Sub vijay1(s 9s Abje.t%e 9s Event9r$s) Handles b.Cli.5
Messa$e;o7.S#o4("Hi1")
End Sub
End Class

For the sake of revision, we add the above three lines of code, just prior to the End Class
statement. The code merely creates a sub vijay1, and employs the 'Handles' keyword to
associate the event Click and object b with the sub. Thus, each time we click on the button,
both subs vijay and vijay1 will be executed. We can associate as many events as we like with
a sub, as has been demonstrated above.

a.vb
8ubli. Class zzz
Wit#Events b as yyy
S#ared Sub Main()
end sub
Sub vijay() Handles b.e
End Sub
End Class
0ubli. .lass yyy
Event e()
end .lass
.lass aaa
in#erits yyy
Sub ab.()
:aiseEvent e()
End Sub
end .lass

$rror
244258241.doc 57 od 272
c:\il\a.vb%#4& : error BC3002@: 6erived classes cannot raise base class events.

Earlier, the class yyy had a sub that raised an event using the statement RaiseEvent, with
event e in the same class. In the above example, the RaiseEvent statement raises an event e
defned in the base class. This is forbidden, as has been indicated by the error message.
Thus, we can only raise events in the very class in which they have been created.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
Sub vijay() Handles bBe
System.Console.WriteLine("Hi")
End Sub
End Class

$rror
c:\il\a.vb%'& : error BC302>=: '.' e0!ected.

The ! symbol placed between the name of the WithEvents object and the name of the event,
is invalid. The only permissible separator is the dot sign.
4. Access ModiBers

Wherever we may venture these days, there is an exorbitance of security. Barely a few are
allowed access to the resources that are considered vital. Programming languages like VB
also implement similar curbs. Access is denied to code that is crucial, in order to evade
transgression.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy ne4 yyy
a.i 10
End Sub
End Class
.lass yyy
dim i as inte$er
end .lass

$rror
c:\il\a.vb%4& : error BC303@0: '+++.i' is not accessible in t.is conte0t because it is
'8rivate'.

In this example, we have a class yyy with an instance variable i of type integer. In the sub
Main within zzz, an instance variable 'a' of type yyy is declared and instantiated
simultaneously. This act saves us one line of code.

On the next line, we attempt to initialize the instance variable i to a value of 10. On doing
so, we get an error message informing us about the non-accessibility of the variable, since it
is 'private'. This error does not occur when we initialize the variable 'a'.

In VB, every entity that is created, is marked 'private' by default. Thus, in class yyy, the
integer variable i is private, and therefore, completely inaccessible. However, the same rules
244258241.doc 58 od 272
do not apply to members of the same class. So, if there had been more members of class
yyy, they could have accessed the integer i with ease.

This privilege is granted exclusively to the members of the class. It is not even extended to
the derived classes or the objects of the class.

On adding the modifer 'public' to the variable, as in "Public dim i as integer", the error
vanishes.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
.lass 777
6n#erits yyy
sub ab.
i 10
end sub
end .lass
.lass yyy
0rote.ted dim i as inte$er
end .lass

The modifer of 'public' allows access to all and sundry, whereas, the modifer of 'protected'
allows only the derived classes to access the variables.

The class yyy has a 'protected' variable i of type integer. The class xxx derives from the class
yyy, since it has the clause of 'inherits' added to it. Due to this, it inherits all the members
contained in the class yyy. If we now initialize the variable, no errors are generated.

This is because the variable is marked as 'protected', in the absence of which, the same
error as depicted above, would have been displayed. Also, creating an instance of the class
xxx, does not allow access to the protected variables. The keyword DIM is optional, when
used in consonance with access modifers.

b.vb
0ubli. .lass yyy
+riend i as inte$er
sub ab.
i 100
end sub
end .lass

We start by compiling the above program b.vb, to create a dll using the following command:

>vbc Ctar1et:librar+ b.vb

The fle b.dll contains a sub abc, which initializes the instance variable i to 100. Note that
the instance variable is declared as a 'friend'. The program a.vb given below, refers to this
'friend' variable and amends its value to 10.

a.vb
8ubli. Class zzz
S#ared Sub Main()
244258241.doc 5" od 272
dim a as yyy ne4 yyy
a.i 10
End Sub
End Class

>vbc a.vb Cr:b.dll

On compiling, the following error is reported:

$rror
C:\il\a.vb%4& : error BC303@0: '+++.i' is not accessible in t.is conte0t because it is
'8rivate'.

The 'friend' access modifer signifes that none other than the entities in the same dll or
assembly can access its variables. Since the instance variable i is being accessed from
another assembly named 'a', an access violation is reported.

The basic rule is being reiterated wherein, the same class is allowed total access to any
member. This behavior is at one extreme of the security spectrum. At the other extreme lies
the 'public' modifer where no rules are applicable.

The 'protected' modifer rests in the middle wherein, just as in the case of 'private', the
derived classes are permitted access to the 'protected' members in the class. Members with
the 'friend' modifer, are accessible from the same assembly that contains their declaration.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy ne4 yyy
a.ab.(100)
a.ab.("#i")
End Sub
End Class
.lass yyy
Averloads sub ab.( i as inte$er)
System.Console.Writeline("yyy ab. &0' " % i)
end sub
Averloads sub ab.( s as strin$)
System.Console.Writeline("yyy ab. &0' " % s)
end sub
end .lass


ut!ut
+++ abc #00
+++ abc .i

This program certainly is no path-breaker. The class yyy has two subs with the same name
of 'abc', but with diferent parameter types. Moreover, a new keyword of 'Overloads' has been
incorporated within the function.

The main function in the class zzz frst creates an instance variable 'a' of type yyy.
Thereafter, it calls the function abc twice, but each time, it uses distinct parameters.

244258241.doc !# od 272
The keyword 'Overloads' apprizes VB of the fact that the class contains more than one sub
with the same name. This keyword is optional. So, when it is removed, everything would
continue to work as before. However, if we obliterate one of the 'overloads' from any of the
abc functions, the following error would be generated:

Error
.CDilDa.vb(1!) C error ;C(1=0?C sub Eab.E must be de.lared EAverloadsE be.ause anot#er Eab.E is
de.lared EAverloadsE.

The rule is very straightforward: Either use the keyword 'Overloads' in all subs having the
same name, or simply steer clear of it!

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as 777 ne4 yyy
dim b as yyy ne4 yyy
a.ab.
b.ab.
End Sub
End Class
.lass yyy
6n#erits 777
sub ab.
System.Console.Writeline("yyy ab.")
end sub
end .lass
.lass 777
sub ab.
System.Console.Writeline("777 ab.")
end sub
end .lass

,arnin1
c:\il\a.vb%##& : warnin1 BC40004: sub 'abc' conEicts wit. sub 'abc' in t.e base class
'000' and so s.ould be declared 'S.adows'.

ut!ut
000 abc
+++ abc

The above example does not generate any errors, however it displays a warning. A warning is
a very benign complaint. Hence, it allows the compiler to create an executable fle. However,
it is in our own interest that we pay heed to these warnings, because if we snub them now,
there is a strong probability of facing embarrassment at a later stage.

The class xxx is the base class with one sub abc. The class yyy derives from the class xxx,
and it also has one sub called abc. The warning is generated because the subs have the
same name in both, the base class and the derived class. The compiler expects the sub in
the derived class to be assigned a distinct or a new name.

On adding the keyword 'Shadows' to the sub abc, as in 'Shadows sub abc' in the class yyy,
the warning disappears.

244258241.doc !1 od 272
In one of the earlier chapters, we had learnt that a derived class can replace a base class.
Accordingly, we create an object 'a' of type xxx, and initialize it to a derived class object xxx.
Then, the sub abc is called of it.

The output shows that the sub abc from class xxx gets called, even though the object has
been initialized to a yyy object. This is because the data type of the object calling the sub, is
accorded preference over the others. Also, due to the 'shadows' keyword, the compiler refers
to the subroutine abc in the yyy, in a very diferent manner.

The second object 'b' of type yyy calls the sub abc from yyy, since there is no name-clashing
in this respect, and a sub called abc exists in class yyy. If the compile time data type
specifed in the DIM statement and the run time data type stipulated in the 'new' are
identical, it does not create any problems.

The object is created as per the run time data type specifed, when the 'new' statement is
executed. However, we have the option of calling the subs either from the base type or from
the derived type. In this example, the abc subroutine is called from the base type.

In the next round, we would like to call the sub of the run time data type, i.e. yyy, rather
than of the compile time data type, which is the default.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as 777 ne4 yyy
dim b as yyy ne4 yyy
a.ab.
b.ab.
End Sub
End Class
.lass yyy
6n#erits 777
Averrides sub ab.
System.Console.Writeline("yyy ab.")
end sub
end .lass
.lass 777
Averridable sub ab.
System.Console.WriteLine("777 ab.")
end sub
end .lass



ut!ut
+++ abc
+++ abc

The above output confrms that the sub abc called of the object 'a', is from the derived class
yyy. Thus, the code has been called from the derived class and not from the base class.

This has been achieved by adding two keywords of 'Overrideable' and "Overrides'.

244258241.doc !2 od 272
We frst aspire that the abc in the base class xxx should allow the derived classes to override
it. To implement this, the sub abc in class xxx must contain the keyword 'Overridable'. This
keyword informs the compiler that the sub abc allows derived classes to override it.

This is not all! The derived class must also state expressly that it wants to override the abc
sub in the base class. For this very reason, the Overrides keyword has been employed. Thus,
the object 'a' now calls the sub abc from yyy, which is the run time type.

The presence of both the keywords 'Overridable' and 'Overrides', is absolutely imperative. If
the 'Overrides' keyword is omitted in the derived class, the default keyword of 'shadows' will
be pressed into action. As a consequence, the compile time data type would then take
precedence. Thus, the sub abc will be called from the class xxx. However, if we specify the
'Overrides' keyword in the derived class and omit the 'Overridable' keyword from the base
class, it will result in the following error:

$rror
c:\il\a.vb%##& : error BC3#0>?: 'abc' overrides a sub in t.e base class '000' t.at is
not declared 'verridable'.

This error signifes that the base class must authorize the derived classes to override its
members. The derived class would then be free to decide whether it wants to override it or
not.


On certain occasions, there exists specifc code that must not be overridden under any
circumstances. Under such situations, the base class can simply ignore the 'Overridable'
keyword, thus eschewing such a eventuality altogether.

One more combination that is not permissible with the sub abc in class yyy is 'Overrides
Shadows sub abc'.

The error message generated is self-explanatory:

$rror
c:\il\a.vb%##& : error BC3#40>: 'verrides' and 'S.adows' cannot be co)bined.

The keyword 'Shadows' conceals the derived class sub name from the base class, whereas,
the 'overrides' does just the reverse! The 'Overrides' keyword ensures that it is the sub from
the derived class that gets called, and not the one from the base class. Thus, these two
keywords are totally incompatible with each other.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as 777 ne4 yyy
a.ab.
End Sub
End Class
.lass yyy
6n#erits 777
AverLoads Averrides sub ab.
System.Console.Writeline("yyy ab.")
My;ase.ab.
end sub
244258241.doc !3 od 272
end .lass
.lass 777
overridable sub ab.
System.Console.Writeline("777 ab.")
end sub
end .lass

ut!ut
+++ abc
000 abc

We have a single object 'a' of type xxx, which is initialized to a yyy type. Now, when the abc
subroutine is called, it gets called from the class yyy, and not from the base class.

Nevertheless, at times, we would want to explicitly call the base class, instead of the derived
class. To do so, the 'MyBase' keyword is used in the derived class containing the sub. The
'OverLoads' keyword is optional. So, even when there is no recurrence of the abc subroutine,
it brews no trouble.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as 777 ne4 yyy
Ea.ab.
End Sub
End Class
.lass yyy
6n#erits 777
AverLoads Averrides sub ab.
System.Console.Writeline("yyy ab.")
My;ase.ab.
end sub
end .lass
.lass 777
0rote.ted overridable sub ab.
System.Console.Writeline("777 ab.")
end sub
end .lass

ut!ut
c:\il\a.vb%@& : error BC302??: '8ublic verrides verloads Sub abc%&' cannot
override '8rotected verridable Sub abc%&' because t.e+ .ave diFerent access
levels.


One minor rule related to overriding is that, the access modifers to the functions must
remain the same. In the above example, the sub abc contains the access modifer of
'protected', which is not present in the derived class, and thereby yields the error.

Thus, the access modifers to the function or to the sub, must be the same or else, an error
gets generated.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as zzz
i+ a is not#in$ t#en
244258241.doc !4 od 272
System.Console.WriteLine("/irst")
end i+
a ne4 zzz
i+ a is not#in$ t#en
System.Console.WriteLine("Se.ond")
end i+
End Sub
End Class

ut!ut
4irst

In this chapter, the above program commenced by declaring a zzz object named 'a'. The
object is yet to be initialized, and upto this point, it is devoid of any value.

This can be substantiated by using the 'is nothing' clause in an 'if' statement. The 'is'
operator ascertains whether the object on the left has the value of the entity specifed on the
right or not.

The word 'nothing' is a keyword, which represents an uninitialized value. Accordingly, the
frst 'if' statement returns a true, while the second 'if' statement returns a false, as the
object 'a' has now been initialized.



a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as inte$er
i+ a is not#in$ t#en
System.Console.WriteLine("/irst")
end i+
End Sub
End Class

$rror
c:\il\a.vb%4& : error BC30020: 'Is' re<uires o!erands t.at .ave reference t+!es9 but
t.is o!erand .as t.e value t+!e 'Inte1er'.

We start by declaring 'a' as an integer, and then, deploy the same 'is' operator on it. An error
gets reported because the 'is' operator works only on reference types, and not on value
types.

There are two basic types in VB:
The value types or the inbuilt types that we encountered earlier, where only the DIM
keyword is sufcient to create variables, without the need of any instance or of 'new'.
The reference types that include the user-defned ones, and the other types that do
not fall within the purview of value types.

a.vb
*aaa)8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
.lass aaa
6n#erits System.9ttribute
244258241.doc !5 od 272
end .lass

Any entity placed within angle brackets, is called an 'attribute'. Thus, aaa is an attribute,
which is placed over the class zzz. An attribute signifes a class that has been derived from
the class Attribute, in the System namespace. An attribute has scores of applications, which
we shall delve upon later.

a.vb
E Honey 6 am #ome
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class

No errors are generated in spite of the 'inserted' statement being present on the frst line.
This is because a single inverted comma indicates a comment line, which is completely
ignored by the compiler. Programmers insert comments in order to explicate code.
Also from the comment sign upto the end of the line, the statement gets ignored by the
compiler.

Every programmer is generally under the delusion that someday, someone would read
his/her code and judge him/her to be the smartest programmer to walk the terra-frma! The
explanations placed within comments serve as a lode star, when the existing program has to
be enhanced or modifed, however, this appears to be a real daunting task!

We commenced this book with a simple Visual Basic project, where the last task that we
undertook, was to display a button on our screen. Then, we took a diversion to explore the
language.

This was absolutely imperative since Visual Studio.Net generated a million lines of code
during the creation the form window and the button. It would have been an uphill task to
try and decipher the code in the frst chapter itself, since we were very naive about the
language and its working at that time.

Now that we are comfortable and at home with the concepts of the language, let us
endeavour to discern this code, and also to embellish it with some of our code. Start the
Visual Studio.Net program. The screen that will appear, is evident in screen 4.1.

244258241.doc !! od 272
Sceen 4.1

Our Start page lists only one project, i.e. the one that we recently toiled on. Your screen
could have a list of many such projects.

Click on the project called vvv to arrive at the screen painter, as shown in screen 4.2. Now,
double click on the button.

Sceen 4.2

Doing so, would open up a new window called the code painter and the cursor would get
positioned at the following function:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Messa$e;o7.S#o4("Hi")
End Sub

244258241.doc !7 od 272
We shall be explaining this function shortly, but prior to that, we want you to append the
line MessageBox.Show with "Hi", as the string parameter to it. Now, press the F5 key, which
is a short cut for compiling and running the program. Along the way, we shall introduce you
to a number of these short cuts, which shall step up your pace of working with Visual
Studio.

On clicking the button, a message box appears, which is similar to what we had
encountered in the Events section. Now, close the application and revert back to Visual
Studio. The code that is displayed in the window, is shown in the screen 4.3.

Sceen 4.3

Select the entire code and paste it into an editor, such as Notepad.

You may also click on the 'plus' sign and view the actual code generated by the framework.
We have reproduced the code below, after stripping away the superfuous portions.

/orm1.vb
8ubli. Class /orm1
6n#erits System.Windo4s./orms./orm
G:e$ion " Windo4s /orm 2esi$ner $enerated .ode "
8ubli. Sub 3e4()
My;ase.3e4()
E-#is .all is re1uired by t#e Windo4s /orm 2esi$ner.
6nitializeCom0onent()
E9dd any initialization a+ter t#e 6nitializeCom0onent() .all
End Sub
E/orm overrides dis0ose to .lean u0 t#e .om0onent list.
8rote.ted Averloads Averrides Sub 2is0ose(;y<al dis0osin$ 9s ;oolean)
6+ dis0osin$ -#en
6+ 3ot (.om0onents 6s 3ot#in$) -#en
.om0onents.2is0ose()
End 6+
End 6+
My;ase.2is0ose(dis0osin$)
End Sub
/riend Wit#Events ;utton1 9s System.Windo4s./orms.;utton
E:e1uired by t#e Windo4s /orm 2esi$ner
244258241.doc !8 od 272
8rivate .om0onents 9s System.Com0onentModel.6Container
E3A-EC -#e +ollo4in$ 0ro.edure is re1uired by t#e Windo4s /orm 2esi$ner
E6t .an be modi+ied usin$ t#e Windo4s /orm 2esi$ner.
E2o not modi+y it usin$ t#e .ode editor.
*System.2ia$nosti.s.2ebu$$erSte0-#rou$#()) 8rivate Sub 6nitializeCom0onent()
Me.;utton1 3e4 System.Windo4s./orms.;utton()
Me.Sus0endLayout()
E
E;utton1
E
Me.;utton1.Lo.ation 3e4 System.2ra4in$.8oint(>>% ?H)
Me.;utton1.3ame ";utton1"
Me.;utton1.-ab6nde7 0
Me.;utton1.-e7t ";utton1"
E
E/orm1
E
Me.9utoS.ale;aseSize 3e4 System.2ra4in$.Size(,% 1()
Me.ClientSize 3e4 System.2ra4in$.Size(!?!% !I()
Me.Controls.9dd:an$e(3e4 System.Windo4s./orms.Control() &Me.;utton1')
Me.3ame "/orm1"
Me.-e7t "/orm1"
Me.:esumeLayout(/alse)
End Sub
GEnd :e$ion
8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Messa$e;o7.S#o4("Hi")
End Sub
End Class

The code produced here is without the redundant blank lines. We believe that unless we
have deciphered the code generated by the framework, we would never be at ease with the
product. Besides, without a thorough understanding, it becomes exceedingly arduous to
augment the existing code.

The code begins with a class called Form1, which is derived from the class Form. Since the
'imports' statement is absent, the Form class is prefaced with the namespace. Any line
beginning with the # character is called a 'directive'. Thus, #Region is a directive, which as
usual, ends with End Region. Clicking on the plus sign with # Region for Windows Form
Designer in Form1, would result into a display of the code generated by the framework.

Thus, whenever the Region directive is encountered, all the code following it upto the 'End
Region' directive, is concealed. Furthermore, any string placed after the Region directive
within the code, is displayed as help. This feature facilitates segregation of code of certain
types. Thus, by placing the Region directive in a class, it becomes much more convenient to
expand and contract the code of a class. Also, it enables the code painter to display a larger
number of program lines, since there is not much space available on the screen. In this
case, the Region directive encapsulates all the code generated by Visual Studio.Net.

There is no Sub named Main visible anywhere in this generated code. However, its existence
is taken for granted. The constructor or the sub 'new', is the frst one to be executed. The
code embodied in it frst calls the original constructor from the Form class, which is
optional. Then, it proceeds to call the function InitializeComponent. Let us now press on
with this function.

244258241.doc !" od 272
The Sub InitializeComponent is private, and it is tagged with an attribute of
DebuggerStepThrough from the namespace System.Diagnostics. At this stage, this attribute
does not assume much signifcance, and even if we delete it, heaven will not fall upon our
heads!

Thereafter, a new instance of a Button object called Button1 is created. Button1 now
becomes an instance variable, defned with the 'friend' access modifer and the 'WithEvents'
keyword, which allows the object to handle events. The software developer who wrote this
program to generate the VB code, was over-cautious and thus, tagged everything with the
word 'Me'; however, this can be safely ignored.

A large number of controls can be added to the form, but with the addition of every control,
the form has to be redrawn. This makes the User Interface extremely clumsy and unwieldy.
So, in order to suspend the process of laying out the Controls on the form, the Form
designer is requested to suspend drawing, till all controls have been rested in place. They
can all be designed in one single stroke.

The function SuspendLayout ensures that the Layout process is suspended for the moment.
Once the code for all controls has been entered, the function ResumeLayout is executed,
thus signaling the Form to display all the controls.

The Code Writer writes the code in a very systematic manner. First, the mandatory button
properties such as Location, Name, Text and TabIndex are initialized to specifc values. The
TabIndex property is used to determine the control that should gain focus, whenever the tab
key is pressed. For the moment, the 'name' property is not used.

Then, the Form properties such as ClientSize and AutoScaleBaseSize are initialized. The
ClientSize property determines the initial window size, whereas, the AutoScaleBaseSize
member decides the minimum size to which the form window can be minimized.

The AddRange function is passed an array of Controls, which currently has only one
member of the Button object, since the form has only a single control placed on it. The title
of the Form is also set to a value, and like the Button, it is also assigned a name.

Visual Studio.Net is inherently aware that the Click event is the default event for the button.
Therefore, on double clicking on the button, it writes a sub named Button1_Click. The name
consists of the name of button object, followed by the word 'Click'.

This sub is passed two parameters with the 'Handles' keyword, having Button1 and Click,
and thereby handling the click event of the button. Thus, each time the button is clicked,
the Button1_Click sub gets called.

The last function that screams for attention is named Dispose. The language keyword 'new'
creates an object. However, there is no corresponding 'delete' keyword for destroying the
object.

As per the latest trends in programming languages, an object can be created explicitly, but it
is the prerogative of the system to decide when the object should die. In programming
languages, this concept is given the nomenclature of 'garbage collection'. By convention, the
Dispose function is called whenever the objects need to clean things up.


244258241.doc 7# od 272
There can be multiple dispose functions in a program. The word OverLoads is optional,
which you may recall, implies that the Form class has a similar function containing the
keyword 'overridable'. The 'protected' modifer is applied to the function, because the original
sub also contains it.

Then, we check whether the instance variable in the form has been instantiated or not. If
the parameter contains some value, it is assumed that the object has been created. So, the
Dispose function is called of this IContainer object. The line demonstrates good
programming style, which demands that the similar function of the base class be called.

Barring the 'not' keyword that converts a True to False and vice-versa, we have expounded
every single concept in the above code, by means of small program snippets. Our approach
in the remaining chapters would be to build VB applications, and simultaneously, attempt at
comprehending the VB code that gets generated.

Our programs will be pint-sized, since only then is it feasible to explicate the concept lucidly.
We will go to the extent of explaining every keystroke that is pressed. So, if you follow our
instructions meticulously to the 'T' and not go astray, you would be able to build complex
windows applications with considerable ease.

$t %ou&d be a eve&ation to you that %hen %e began &eaning a 'oduct &ike (isua& Studio.)et*
%e +ound it s&ight&y com'&icated. ,his %as because the diminutive detai&s o+ the 'oduct had
to be unave&ed* %hi&e tying to &ean the a''oach that (isua& Studio.)et e-'ected us to
ado't. ,hee+oe* %e have tied to make this voyage as com+otab&e as 'ossib&e +o you.
'. 6atabase A!!lications

This chapter focuses on building applications that interact with data stored in databases.
However, prior to plunging right in, we need to understand the new concepts of Properties
and Indexers, which we would be bumping into with a surprisingly high frequency, in this
application.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.ab.)
end sub
end .lass
0ubli. .lass yyy
+un.tion ab. as inte$er
System.Console.WriteLine(";e+ore ab.")
ab. !00
return 1!0
System.Console.WriteLine("9+ter ab.")
end +un.tion
end .lass

ut!ut
Before abc
#20
244258241.doc 71 od 272

In the above example, we revisit the concept of a function, which is a sub with a return
value. A function can return values by assigning a value to the function name. There is
nothing incongruous about this procedure of sending back values. However, there is an
alternate approach that is pursued by most of the programming languages, i.e. the use of
the 'return' statement.

In the above program, the function name is set to a value of 200, which becomes the return
value. However, on the next line, we come across a return statement containing a value of
120. On encountering the 'return' keyword, all execution of code in the function ceases, and
the value of 120 is returned. Thus, the WriteLine function in main, displays the value of
120.

Note that the last WriteLine function in abc, does not get executed. A return statement is
used to return values. The code that is positioned after the 'return' statement, never gets
executed.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.aa)
a.aa 100
System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
8ubli. 8ro0erty aa() 9s 6nte$er
Jet
System.Console.WriteLine("$et")
:eturn 10
End Jet
Set (i 9s 6nte$er)
System.Console.WriteLine("set &0'"%i)
End Set
End 8ro0erty
end .lass

ut!ut
1et
#0
set #00
1et
#0

Although the instance variables are very handy, they have two major faws:
Firstly, there is no way of executing any code of our own, when the variable is being
accessed. Owing to this limitation, we are never notifed about the changes that the
variable undergoes. Thus, no action can be taken when the value changes.
Secondly, there is no means of performing any error checks on the value. Thus, if the
value goes beyond a certain range, no corrective action can be initiated.

244258241.doc 72 od 272
The solution to both these foibles can be seen in the above example, where a yyy object is
created; thereafter, the value of the aa member is displayed. Superfcially, the syntax that is
used, appears to be analogous to the one used with instance variables.

However, the code reveals that aa is a property that returns an integer. Its syntax has two
accessors, a Get and a Set accessor. The code between the Get and End Get gets called
whenever the value of the property has to be retrieved; and the code within Set and End Set
gets executed when a value is assigned to the variable.

Each of these accessors could contain a million lines of code. Furthermore, the Get accessor
uses the 'return' statement, where the value to be returned is the current value in the
property. This explains why the value of 10 is displayed by the WriteLine function.

On the face of it, a property behaves just like an instance variable. It is initialized in a
fashion similar to that of a normal variable, except for the fact that the Set accessor code
gets executed when the value is assigned. Thus, the variable i will now hold a value of 100.
We have not executed any other task here. Therefore, the fnal value displayed is 100 and
not 10. However, in real life, this value must be stored for further processing. The next
program fxes this minor fault.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.aa)
a.aa 100
System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
dim ii as inte$er !00
8ubli. 8ro0erty aa() 9s 6nte$er
Jet
System.Console.WriteLine("$et")
:eturn ii
End Jet
Set (i 9s 6nte$er)
System.Console.WriteLine("set &0'"%i)
ii i
End Set
End 8ro0erty
end .lass

ut!ut
1et
200
set #00
1et
#00

In this program, 'a' is an object of class yyy. After creating the object, the value contained in
the aa variable is frst displayed. Then, the aa member in the object is initialized to 100.
Finally, the value of aa is displayed. At this stage, it is well nigh impossible to distinguish
whether aa is an instance variable or a property.

244258241.doc 73 od 272
However, the class yyy clears away the mist of perplexity. When the yyy object is created, an
instance variable ii is set to the value of 200. Now, to display the value of the property aa,
the Get accessor is called, which returns the value of ii, i.e. 200. Thus, even when the
property is not initialized, its value is displayed as 200.

When aa is assigned a value of 100, the Set accessor of aa is called. The value of 100 is
passed as a parameter to Set. This is verifed by displaying the value of the parameter i.
Subsequent to this, the instance variable ii is assigned this value. In the next round, when
the value of the property aa has to be retrieved, the value of ii in the Get accessor shall be
100. Thus, the Get accessor returns the updated value of the variable ii, which is set in the
Set accessor code.

In order to store the value assigned to the property, the presence of an instance variable in
this class is imperative. In the same vein, any amount of code can be supplied in the
accessors. This code will be executed when the value of the property is either set or is
retrieved.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.aa)
a.aa 100
System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
dim ii as inte$er !00
8ubli. 8ro0erty aa() 9s 6nte$er
Jet
System.Console.WriteLine("$et")
:eturn ii
End Jet
Set (i 9s 6nte$er)
System.Console.WriteLine("set &0'"%i)
i+ i * ,0 t#en
ii i
else
ii ,0
end i+
End Set
End 8ro0erty
end .lass

ut!ut
1et
200
set #00
1et
'0

In the above example, we perform a check on the value assigned to the property. In the Set
accessor, if the value of the property aa is ever set to 50 or more, the value of the instance
variable is confned to 50. This occurs only when the Set accessor is called, i.e. at the time
244258241.doc 74 od 272
of assignment. The Get would frstly display the initial value of variable ii, which is set to
200.

Now, when a value of 100 is assigned to the property, the 'if' statement in the Set returns
False, thereby executing code in the 'else' clause. As a result, the value of ii is set to 50.
Thus, the error check in the Set accessor introduces some sanity, wherein the user is
allowed to change a particular value.

The best example of this is the GraphType. Altering its value would lead to the execution of a
considerable amount of code, which eventually redraws the graph with the new type that is
specifed. At this point, the values need to be validated, since they cannot go beyond their
bounds.

Thus, the beauty of properties is that, they provide us with instant feedback.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
dim ii as inte$er !00
8ubli. 8ro0erty aa() 9s 6nte$er
Jet
System.Console.WriteLine("$et")
:eturn ii
End Jet
End 8ro0erty
end .lass

$rror
c:\il\a.vb%#0& : error BC30#24: 8ro!ert+ wit.out a 'Deadnl+' or ',ritenl+'
s!eciBer )ust !rovide bot. a 'Get' and a 'Set'.

Due to the absence of the Set accessor in the example just discussed, the above error is
generated. We have not expounded this error message on purpose, since it is self-
explanatory.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
dim ii as inte$er !00
8ubli. :eadAnly 8ro0erty aa() 9s 6nte$er
Jet
System.Console.WriteLine("$et")
:eturn ii
End Jet
End 8ro0erty
244258241.doc 75 od 272
end .lass

ut!ut
1et
200

There could be many situations wherein we would want to display a property to the user,
but would not want the user to change its values. An answer to this would be to defne the
property as ReadOnly.

In this case, the above property shall always have a value of 200. Therefore, we can get rid of
the instance variable ii. All the other advantages of properties remain untouched.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
a.aa 100
E System.Console.WriteLine(a.aa)
end sub
end .lass
0ubli. .lass yyy
8ubli. WriteAnly 8ro0erty aa() 9s 6nte$er
Set ( i as inte$er )
System.Console.WriteLine("set &0'" % i)
End Set
End 8ro0erty
end .lass

ut!ut
Set #00

Similar to the ReadOnly property is the WriteOnly property. In WriteOnly property, the only
option available to the user is, to change the value of the property.
The above program reveals the fact that, we are permitted to set the value of the property to
100. There are a very few such situations, wherein you may like to use a WriteOnly property.

Now, remove the comment from the above program. On doing so, the screen flls up with
errors akin to the one displayed below:

'8ublic S.ared verloads Sub ,rite-ine%for)at As Strin19 8ara)Arra+ ar1%& As
b*ect&': 8ro!ert+ 'aa' is ',ritenl+'.

This ensues because of the property aa being WriteOnly. Thus, under no circumstances are
we allowed to display its value.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
a.aa("Hi") 100
System.Console.WriteLine(a.aa(";ye"))
end sub
end .lass
244258241.doc 7! od 272
0ubli. .lass yyy
8ubli. 8ro0erty aa(i 9s strin$) 9s 6nte$er
Jet
System.Console.WriteLine("Jet &0' " % i )
:eturn !,
End Jet
Set (;y<al v 9s 6nte$er)
System.Console.WriteLine("Set &0' &1'" % i % v)
End Set
End 8ro0erty
end .lass

ut!ut
Set "i #00
Get B+e
2'


Another advantage of using properties is that, they can accept parameters. The above
example has the property 'aa', which is called with a string parameter.

The property defnition is now amended to accept parameters, in a manner similar to a
function. Thus, while setting the value for the property aa, the parameter value of "Hi" is
assigned to it. The value in the parameter is accepted in the string variable i, which is
displayed using the WriteLine function. In a similar manner, the Get accessor is called with
the value of "Bye".

This method is exploited very often, whenever the class represents a record from a table. The
parameter is a string that denotes the feld name whose value we may wish to retrieve or set.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as yyy
a ne4 yyy
a(10) 100
a.6tem(!0) !00
System.Console.WriteLine(a((0))
end sub
end .lass
0ubli. .lass yyy
2e+ault 8ubli. 8ro0erty 6tem(i 9s 6nte$er) 9s 6nte$er
Jet
System.Console.WriteLine("Jet &0' " % i )
:eturn !,
End Jet
Set (;y<al v 9s 6nte$er)
System.Console.WriteLine("Set &0' &1'" % i % v)
End Set
End 8ro0erty
end .lass

ut!ut
Set #0 #00
Set 20 200
Get 30
2'
244258241.doc 77 od 272

The above program has a property called Item, which accepts one parameter of type integer.
Moreover, it has a new keyword called 'default' added to it. When a property is marked as
'default', it requires a parameter; but more importantly, it signifes that this property name
can be omitted.

The property gets called when the yyy instance 'a' is used with the parameter, however,
without a property name. When we come across the line a(10) = 100, Visual Basic.Net hunts
for a property that has the 'default' keyword attached to it. Since the Item property has this
tag added to it, the Set accessor of this property gets called. In the same way, the Get
accessor gets called when the WriteLine function is executed.

However, nothing prevents us from using the property name as in a.Item(20). This is
permissible, even though the property name is 'defaulted'. The concept of 'default' is also
known as an Indexer in languages, such as C#. It is one of the various novel features of the
modern programming language theory.

If there are two properties with the same modifer of 'Default', the following error is
reported :

c:\il\a.vb%20& : error BC303'@: '6efault' can be a!!lied to onl+ one !ro!ert+ na)e
in a class.

This appears logical, since only a single property can be the default value. If there happen to
be two default values, it results in a dilemma as to which property is to be used. It is also
mandatory to assign a parameter to the property. If this is not done, the following error will
be reported :

2e+ault 8ubli. 8ro0erty 6tem() 9s 6nte$er

c:\il\a.vb%##& : error BC3#04>: 8ro!erties wit. no re<uired !ara)eters cannot be
declared '6efault'.

After having elucidated these concepts on properties and indexers, we progress on to the
next program, which displays data in a grid. This data is retrieved from a database, and
stored in a database.

a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
0ubli. .lass zzz
6n#erits /orm
2im d as 2ataJrid
dim . as 2ataSet
26M .on as S1lConne.tion
dim .ust as S1l2ata9da0ter
sub ne4()
d ne4 2ataJrid()
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
.on ne4 S1lConne.tion("uidsaLdatabasenort#4ind")
244258241.doc 78 od 272
.ust ne4 S1l2ata9da0ter ("Sele.t @ +rom Customers"% .on)
. ne4 2ataSet()
d.2ataSour.e .
Cust./ill(.% "...")
d.2ataMember "..."
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
end .lass

When we run the above program, we see a window with a data grid, displaying data in the
rows and columns format.

Let us unravel the mystery behind how the above program works its magic.
The program begins with six import statements, since it employs the classes that belong to
them. It is extremely cumbersome to recall the namespace that the class belongs to.
Therefore, the help on the classes can be consulted, which not only provides the name of the
namespace, but also enlightens us about the name of the assembly or dll fle in which the
code resides. There are far too many classes that Visual Basic.Net employs. So, it is futile to
even attempt committing any of them to memory.

We have adopted the following approach: We incorporate a class in the program. If the
compiler reports an error, we look up the help on the class, which not only divulges the
name of the namespace, but also makes known the assembly encompassing its code. The
namespace is added to the code using the import statement, and the assembly is provided
to the compiler with the /r: option.

After determining all the namespaces and the dll fles that are required, the fnal compiler
command looks like the followings:

vbc a.vb Cr:S+ste).,indows.4or)s.dll Cr:S+ste).dll
Cr:S+ste).6rawin1.dll Cr:s+ste).data.dll Cr:S+ste).HM-.dll

Sceen 5.1

Four objects named d, c, con and cust are declared. Each of them is assigned a special role
to play. We shall systematically explain their signifcance.

244258241.doc 7" od 272
The class zzz inherits from the Form object, thereby including all the members of the Form
class. In the Sub main, 'a' is created as an object of type zzz, which is then provided as a
parameter to the Run function in the Application class. While creating the object, the
constructor or the 'new' function of zzz, gets called. In this sub, a DataGrid object is
instantiated. The DataGrid class contains code that performs certain tasks, such as,
displaying data in rows and columns format.

The Size property is set to display the data grid within a specifed area. Most properties have
a default size. However, in the case of the DataGrid, the default size is too diminutive for our
liking. The ClientSize property determines the size for the entire window, which is also set to
a new value, since the default size is too small.

The SqlConnection object is the next in line to be created. It is this object that connects to
an SQL Server database. While connecting to the SQL Server, this class requires certain
data, such as the userid, the password, the database, etc. This is because a database is
susceptible to access by trillions of people. Thus, to maintain integrity of data, only
authorized users should be allowed access to it. For the neophytes of the database world,
Oracle and SQL Server are the two largest database products in the world. A database
server is a program that can store stupendous quantities of data.

The string passed to the SqlConnection constructor is called a 'connection string', which
uses the semicolon symbol as a separator or delimiter. The word uid is an option given with
the connection and it represents the user name.

Every database or operating system, or any multi-user entity, has a specifc user, for whom
no rules are applicable. In Oracle, this user is known as 'System', while in SQL Server, it is
known as 'sa'. Thus, the user 'sa' is logging into the database. It does not possess any
password, because while installing the server, we selected the blank password option.
We are aware that this is indeed a very dumb act to perform and it is unlikely to transpire in
real life. However, while writing this book, we wanted to avoid all complications, and hence,
we left it blank.

The data that is stored in the tables, requires to be logically grouped, similar to the manner
in which classes are grouped within namespaces. This concept is termed as 'databases',
implying that the data would be stored in tables within a particular database in SQLServer.
The string has the database connection option, which is set to the database named
Northwind, from which, tables would be extracted for use.

The lone object that we have achieved so far is that, we have framed the connection string in
the SqlConnection class, and have stored the result in the SqlConnection object 'con'. We
have not made any attempt to connect to the database as yet.

To execute this activity, an instance of SqlDataAdapter is created and stored in the variable
called 'cust'. The constructor is assigned two parameters; the frst parameter is a string and
the second one is the freshly created SqlConnection object called 'con'.

The string in the frst parameter informs the SqlDataAdapter class about the data that
needs to be retrieved from the database. Hence, it has to be specially constructed in
accordance with the rules of SQL, i.e. Structured Query Language. Tons of pages have been
written about SQL. However, it shall be our endeavour to explain SQL in less than 50 words.

244258241.doc 8# od 272
The word Select is used in SQL languages to retrieve data from a database. Following this,
the feld or column names that are to be retrieved, are specifed. The * sign represents all
the columns in the table. The word 'from' is part of the syntax. It has to be followed by the
name of the table of the database. Here, the table Customers is specifed. These databases
have already been created and flled with data during the installation of the server.



Thereafter, the SqlDataAdapter object collects the following:
The SQL statement, which is used for retrieving data.
The connection object, which is used for connecting to SQL server.

Once the connection string is prepared and the data retrieval syntax is ready in all respects,
a DataSet object is created, which represents the data collected from various tables. A table
represents a single set of logical data, while a data set represents scores of such tables.

The data grid has a DataSource property that is set to the DataSet c, since it is the dataset
that would fnally contain the data to be displayed in the grid. The Fill function in the
SqlDataAdapter object 'cust', actually flls the DataSet object with data. In our case, an
arbitrary name of ccc is assigned to the table.

The Fill function fnally commences all the activities. Using con, a connection is established
with the SQL Server. Then, the Select statement is executed to retrieve data from the
database. The data that is returned, is a list of customers retrieved from the Customers
table. This data is stored in the dataset, under the name of 'ccc'.

A DataSet is merely a collection of tables. Now, to display data from this set, the
DataMember property is initialized to the dataset object ccc. Finally, only the data-grid
control is added to the Form, using the Controls collection.

In this manner, a DataGrid control can be employed to display the data from a database.

a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
0ubli. .lass zzz
6n#erits /orm
2im d as 2ataJrid
dim . as 2ataSet
26M .on as S1lConne.tion
dim .ust as S1l2ata9da0ter
dim d1%d! as S1l2ata9da0ter
sub ne4()
d ne4 2ataJrid()
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
.on ne4 S1lConne.tion("uidsaLdatabasenort#4ind")
.ust ne4 S1l2ata9da0ter ("Sele.t @ +rom Customers"% .on)
d1 ne4 S1l2ata9da0ter ("Sele.t @ +rom 8rodu.ts"% .on)
d! ne4 S1l2ata9da0ter ("Sele.t @ +rom Em0loyees"% .on)
. ne4 2ataSet()
244258241.doc 81 od 272
d.2ataSour.e .
Cust./ill(.% "...")
d1./ill(.% "ddd")
d!./ill(.% "eee")
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
end .lass

In the above example, two additional SqlDataAdapter objects, d1 and d2 are created. The
constructors are given the same SqlConnection object, but with diferent table names of
Products and Employees in the SQL statement.

Then, the Fill function is used to create two more tables called ddd and ccc, in the DataSet
object c. Thus, the DataSet object now has three tables within it.

Here, the line initializing the DataMember property, has also been deleted. On running the
above program, a window will be displayed, as shown in screen 5.2.

Sceen 5.2

The only thing that is apparent in the window is a 'plus' sign, since the Data Member is not
initialized.

This sign is an indication to the DataGrid, that the + sign has to be clicked upon, in order to
display the list of tables contained in the DataSet.

244258241.doc 82 od 272
Sceen 5.3

Clicking on the 'plus' sign expands the DataSet to display the three tables. This is shown in
screen 5.3. We have clicked on the last table named eee. Therefore, the screen that pops up,
displays the records from the Products table, as shown in screen 5.4.

Sceen 5.4

If you observe the screen very closely, you would notice an arrow marked to the left. If you
click on the arrow, you would once again land up in screen 5.3. This is how a DataGrid
facilitates switching between tables, when the DataSet comprises of more than one table.

a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
0ubli. .lass zzz
6n#erits /orm
2im Wit#Events d as 2ataJrid
dim . as 2ataSet
26M .on as S1lConne.tion
dim .ust as S1l2ata9da0ter
sub ne4()
d ne4 2ataJrid()
d.9lternatin$;a.5Color Color.:ed
d.;a.5Color Color.;lue
244258241.doc 83 od 272
d.;a.5$roundColor Color.Jreen
d.Ca0tion/oreColor Color.;la.5
d.Ca0tion;a.5Color Color.W#ite
d.Ca0tion-e7t "<ijay Mu5#i"
d.Ca0tion<isible true
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
.on ne4 S1lConne.tion("uidsaLdatabasenort#4ind")
.ust ne4 S1l2ata9da0ter ("Sele.t @ +rom Customers"% .on)
. ne4 2ataSet()
d.2ataSour.e .
Cust./ill(.% "...")
d.2ataMember "..."
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
sub ab.(s as obje.t % e as MouseEvent9r$s ) Handles d.Mouse2o4n
System.Console.WriteLine("&0' &1' &!' &('" %e.K % e.M % e.Cli.5s % e.;utton)
end sub
end .lass

ut!ut
#== '0 # -eft
20> ##2 2 Di1.t

The above DataGrid example consists of a variety of colors. First of all, the Background color
is set to green, by initializing the BackgroundColor property to Green. This property is a
shared instance member of the class Color. Next, the default BackColor of the row is set to
Blue, and the AlternatingBackColor is set to Red. Every alternate row will have the
background color of red. This completes the coloring of the grids.

The property CaptionText determines the title of the data grid. Here, it is set to "Vijay
Mukhi". The caption is made visible, and the foreground and background colors are
initialized to Black and White, respectively. This is achieved by setting the CaptionForeColor
and CaptionBackColor properties in the datagrid.

The most striking feature of this example is not the setting of the myriad colors, but the
'event handling' of the grid. Since we want the DataGrid object 'd' to handle events, the
WithEvents keyword is specifed with the handler assigned to sub abc, with the object event
of d.MouseDown.

This initialization traps every mouseclick on the grid and calls the function abc. The sub
abc is called with two parameters, where the second parameter 'e' is of type
MouseEventArgs. This object has two properties named X and Y, which store the position of
the mouse click. The Clicks property maintains the count of the total number of clicks.
Finally, the button property apprizes us of whether it was the Right mouse button that was
clicked, or was it the Left mouse button to be clicked.

The output discloses that it was the Right mouse button that was clicked twice, at x and y of
208 and 112. By implementing this feature, we can assist in monitoring the actions of the
user on the data grid.
244258241.doc 84 od 272

a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
0ubli. .lass zzz
6n#erits /orm
2im Wit#Events d as 2ataJrid
dim . as 2ataSet
26M .on as S1lConne.tion
dim .ust as S1l2ata9da0ter
sub ne4()
d ne4 2ataJrid()
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
.on ne4 S1lConne.tion("uidsaLdatabasenort#4ind")
.ust ne4 S1l2ata9da0ter ("Sele.t @ +rom Customers"% .on)
. ne4 2ataSet()
d.2ataSour.e .
Cust./ill(.% "...")
d.2ataMember "..."
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
sub ab.(s as obje.t % e as Event9r$s ) #andles d.CurrentCellC#an$ed
2im $ as 2ataJridCell
$ d.CurrentCell
dim .%r as inte$er
. $.Column3umber
r $.:o43umber
System.Console.WriteLine( "Column &0' :o4 &1' <alue &!'" % . % r % d(r%.))
d(r%.) "#i " & d(r%.)
end sub
end .lass

ut!ut
Colu)n 3 Dow 2 5alue wner
Colu)n 2 Dow 4 5alue C.ristina Ber1lund

A DataGrid object is comprised of multiple objects of type DataGridCell. These objects are
the cells which are at the intersection of a row and a column storing data. Whenever we
click on a cell to change its value, the event CurrentCellChanged gets called. In our
program, we have trapped this event to call the function abc.

The CurrentCell property returns a DataGridCell object, which represents the cell that the
user has currently clicked on. This value is stored in the variable 'g'. Thus, each time a cell
is clicked on, the value of the CurrentCell property is updated, to refect this new cell or
DataGridCell object.

244258241.doc 85 od 272
The DataGridCell object has two properties, named ColumnNumber and RowNumber, which
return integer values representing the column and the row that have been selected. These
values are printed with the help of the WriteLine function, along with the indexer that
accepts a row and column number. The indexer returns the contents of the Cell. To change
the current contents of the cell, the indexer can be reused, with the new value that is to be
assigned.

In Visual Basic.Net, the & sign is utilized to concatenate or join two strings. The indexer for
the DataGrid class is 'read-write'. Hence, it can be used to get a value, as well as, to set a
value.

a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
0ubli. .lass zzz
6n#erits /orm
2im d as 2ataJrid
dim t as 2ata-able
2im r as 2ata:o4
sub ne4()
d ne4 2ataJrid()
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
t ne4 2ata-able()
2im . as 2ataColumnColle.tion
. t.Columns
..9dd("3ame")
..9dd("City")
r t.3e4:o4()
r("3ame") "<ijay"
r("City") ";ombay"
2im r1 as 2ata:o4Colle.tion
r1 t.:o4s
r1.9dd(r)
r t.3e4:o4()
r("3ame") "Sonal"
r("City") "2el#i"
t.:o4s.9dd(r)
d.2ataSour.e t
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
end .lass

244258241.doc 8! od 272
Sceen 5.5

The above example demonstrates the fact, that the data displayed in a data grid may not
necessarily originate from a table in a database. It could originate from anywhere. The
screen 5.5 authenticates this fact.

To implement the above, a DataTable object t is created. The constructor may be passed the
name of the table Control, however, this is optional.

A table is made up of a large number of columns or DataColumn objects, which are
represented by a DataColumnCollection object. The DataTable has a member called
Columns, which returns a DataColumnCollection. Using the Add function in the
DataColumnCollection class, two columns named Name and City are added to the data
table.

Thus, while dealing with a data table object, the basic principle to be kept in mind is that
the properties of the DataTable are to be used, and not the DataTable object itself.

Applying the same principle, records are added to the data table. The NewRow function adds
a new empty row to the DataTable object. Then, using the indexer and assigning it a
parameter of the column name, the columns are individually assigned to some values.

After having initialized the DataRow object, the row now has to be added to the DataTable.
The DataRows are stored in a DataRowCollection object, which can be accessed using the
Rows collection. So, like before, we use the 'Add' function to add the row to the DataTable. In
all, two rows are added to the DataTable. Thus, a DataTable is merely a collection of records,
and it represents records in the same manner in which they are stored in the database.

While retrieving data from the table, the DataSource property was initialized to a data set.
However, when values are assigned individually, a DataTable object is used. Thus, the data
grid object is fexible enough to work with diferent data sources.


a.vb
im0orts System
im0orts System.2ata
im0orts System.2ra4in$
im0orts System.Windo4s./orms
im0orts System.2ata.S1lClient
im0orts System.Kml
244258241.doc 87 od 272
0ubli. .lass zzz
6n#erits /orm
2im d as 2ataJrid
dim . as ...
26M .on as S1lConne.tion
dim .ust % ord as S1l2ata9da0ter
sub ne4()
d ne4 2ataJrid()
d.Size ne4 Size(,>=% ((H)
ClientSize ne4 Size(H00% =1()
.on ne4 S1lConne.tion("uidsaLdatabasenort#4ind")
.ust ne4 S1l2ata9da0ter ("Sele.t @ +rom Customers"% .on)
Ard ne4 S1l2ata9da0ter ("Sele.t @ +rom Arders"% .on)
. ne4 ...
d.2ataSour.e .
d.2ataMember "Customers"
Cust./ill(.% "Customers")
Ard./ill(.% "Arders")
Controls.9dd(d)
end sub
s#ared sub Main()
dim a as zzz
a ne4 zzz
900li.ation.:un(a)
end sub
end .lass
0ubli. .lass ...
6n#erits 2ataSet
dim t. as .us
dim to1 as orders
dim r as 2ata:elation
0ubli. sub ne4
t. ne4 .us("Customers")
-ables.9dd(t.)
to1 ne4 Arders("Arders")
-ables.9dd(to1)
r ne4 2ata:elation(".ustord"%t...62%to1.o62)
:elations.9dd(r)
end sub
end .lass
0ubli. .lass .us
6n#erits 2ata-able
0ubli. dim .62 as 2ataColumn
sub ne4 (n as strin$)
Mybase.3e4(n)
.62 ne4 2ataColumn("Customer62")
Columns.9dd(.62)
end sub
end .lass
0ubli. .lass Arders
6n#erits 2ata-able
0ubli. o62 as 2ataColumn
sub ne4 (n as strin$)
mybase.ne4(n)
o62 ne4 2ataColumn("Customer62")
Columns.9dd(o62)
end sub
end .lass

244258241.doc 88 od 272
The explanation to the above program could run into reams of paper. Therefore, we shall
examine it only after executing the program.

But prior to that, we would like to furnish one crucial bit of information to you, i.e. the
Customer table contains a list of customers, while the Orders table contains the list of
orders that the customer places on a regular basis.

The output displays a list of customers, with a plus sign placed next to it. This is displayed
in screen 5.6.

Sceen 5.!

If we click on the plus sign, custord will be displayed with a link, as shown in the screen
5.7.

Sceen 5.7

When we click on this link, a list of orders placed by the customer will be displayed. Screen
5.8 substantiates this point.

244258241.doc 8" od 272
Sceen 5.8

The above procedure can be repeated for any customer, whose orders need to be viewed.
This example demonstrates how data from diferent data tables, can now be related to each
other.

Most of the code remains unchanged, with the exception of a few additions. An additional
SqlDataAdapter object named ord is created, to represent records from the Orders table. The
major diference is that the class ccc, which is derived from the DataSet class, is employed
in lieu of using the DataSet class directly.

A signifcant advantage of this approach is that, the code that is deemed appropriate from
the DataSet class, can be utilized; whereas, the code that is not considered acceptable, can
be overridden.

Thus, at the very outset, we have created a ccc object. This leads to a call to the constructor
of the ccc class. In the ccc object, three instance objects have been created.


The frst one is of type class cus, which is derived from the DataTable class. The cus
constructor is passed the name of the table, i.e. Customers, which would be considered a
little later, along with the Fill function. Both the names should necessarily be the same, or
else, an exception would be thrown.

Since the cus class is derived from the DataTable class, it represents some data. By
overriding the DataTable class, an additional column can be added to the DataTable. This is
accomplished by creating a DataColumn called CustomerID, and then, by using the add
function to add the column to the Columns collection. Candidly speaking, the sole purpose
of deriving the cus class from the DataTable class is to add a column named CustomerID.

The column CustomerID is visible in both the tables, i.e. Customers and Orders. Hence, it
can be used to relate records in these two tables. In the ccc class, the class cus is added to
the list of DataTables, maintained by the Tables collection of the DataSet class.

Next, we create an object that is an instance of the Orders class. The mechanism of this
object remains analogous to the cus class, where a new column named CustomerID is
introduced. The DataColumn object in both the DataTable classes is an instance variable,
and hence, it is accessible to the other objects.

244258241.doc "# od 272
Now, we descend upon the most crucial lines of the code.

An object of class DataRelation is created, where the frst parameter to the constructor is a
string, denoting the name of the DataRelation. The string assigned here is custord. As an
outcome of this, the hyperlink of custord is revealed when the plus sign is clicked upon.

The next parameter is the DataColumn for the Primary key, which is the column that is
unique. The value assigned in the Customers table is CustomerID, since it is unique for
every customer. The last parameter is the Foreign Key in the second table, which contains
multiple values of the Primary Key. The CustomerID column in the Orders table has more
than one occurrence of the Customer id.


Using the Add function, the relation is then added to the Relations object. This is indicative
of the fact, that there may be many more relations that can be added, once the relation
between the data has been established. The rest of the code remains unaltered. Both, the
primary key and the foreign key need to be represented by DataColumn objects. Therefore,
the two classes of cus and orders have been created.

Having acquired the knowledge of the concepts, by manually creating an application, let us
now allow Visual Studio.Net to create it for us. The application will consist of a Form having
a button and a DataGrid. Once the user clicks on the button, the DataGrid will be sufused
with data from the Database.

What is of prime signifcance here is that, all this transpires without our having to write
reams of code, since it is the framework that handles this task. However, after discerning as
to how the application works, we shall venture forth to unravel the code written by Visual
Studio.Net.

We would implore you not to meddle with the application, till we have accomplished our
task. We have endeavoured to subsume most of the screens for your convenience, thus
eliminating the need to sit in front of the computer while browsing the chapter.

In Visual Studio.Net, you can create a new project by clicking on the menu, File - New -
Project. This opens up the New Project dialog box. In the frst pane, choose Visual Basic
Projects, and in the second pane, choose Windows Applications. Enter t1 as the name of the
project, and point the directory to c:\v1. Then, click on OK. You may wish to select the
project name; however, we would request you to initially accept our names as they are.

You should arrive at screen 5.9, having a mammoth Form and a ToolBox to the left. If for
some reason, you are unable to see the toolbox on the left, click on the menu View, and
select ToolBox. But, if you have toolbox that hides automatically, unselect the option of
AutoHide from the Windows menu option.

244258241.doc "1 od 272
Sceen 5."

The toolbox has millions of controls. Hence, they are located under separate categories or
tabs. The category of Data encompasses all the controls that work with data. Since this
chapter deals with databases, select the Data subhead, and examine the controls stipulated
below it. The screen that we arrive at, is shown in screen 5.10.

Sceen 5.1#

Choose the control called OleDbDataAdapter and place it on the Form. It should be done in
a manner akin to the one employed in the previous chapter, to place a button on the Form.

The procedure remains the same, i.e. click on the control to select it, and then, keeping the
left mouse button pressed, drag and drop it onto the Form. Surprisingly, unlike a button,
the control is not positioned on the Form. Instead, a dialog box pops up, as shown in screen
5.11.

244258241.doc "2 od 272
Sceen 5.11

Here, we are informed in no uncertain terms, that we are in the august presence of Merlin's
Wizard! The job of a wizard is to make our lives easier by using black magic. Thus, a
Microsoft wizard throws a volley of questions at us. Based on the answers furnished by us,
it toils towards ameliorating our lives by writing tons of code to achieve the desired outcome.

By convention, the frst screen of a wizard provides information about the type of the wizard.
Presently, we are not very keen on reading it. So, we click on the Next button. This
transports us to the next step in the wizard, as shown in screen 5.12.

Sceen 5.12

Here, we are asked to confrm which database we prefer to connect to. Since we have not
created any connection in the past, we click on the 'New connection' button to arrive at
screen 4.13.

244258241.doc "3 od 272
Sceen 5.13

The Data Link Properties Dialog Box requires considerable amount of information, before it
can create a new connection. However, all the boxes do not require to be flled up. The server
name is left blank, since the database server runs on the same machine as the application.

A connection is made to the server, employing the user name 'sa'. Therefore, 'sa' is entered
in the textbox labeled 'User Name'. Since the password is set to blank, the Check box for
Blank password is selected. Then, we click on the down arrow of the drop down listbox for
displaying the option of select database on server. The screen 5.14 depicts the outcome of
our action.

Sceen 5.14

The list provided is that of the databases, which have been created on the server. After
having selected the Northwind database, the dialog box looks similar to what is shown in
screen 5.15.

244258241.doc "4 od 272
Sceen 5.15

The program that we had written earlier had incorporated data from the 'Northwind'
database, which is visible in the list. Although we are at liberty to select the database, we
will stick to Northwind for the time being.

An added advantage of a drop down listbox is that, it averts the possibility of a wrong
database name being entered by the user, since a name has to be selected from the list that
is provided.

Now, click on the button labeled Test Connection. This fnally ascertains whether all the
values entered are valid from the standpoint of the database server.

The Screen 5.16 returns with a message of success.

Sceen 5.1!

Some processing had taken place when the Test connection button was clicked.
244258241.doc "5 od 272

This involved connecting to SQL Server using the user name 'sa' and using a blank
password, and thereafter, accessing the Northwind database.

When you click on OK, you will be reverted back to one of the previous screens, with the
name of VMUKHI.Northwind.dbo in the listbox, as shown in screen 5.17.

Sceen 5.17

Vmukhi is the name assigned to our computer. It is followed by the name of the database
Northwind, with an extension of dbo.

Now, click on the Next button to arrive at the screen 5.18. A 'stored procedure' is a program
that resides and executes on the server. We feel quite contented to use the trusted SQL
Select statements to fetch data. So, we simply click on the Next button, without making any
amendments to screen 5.18.

Sceen 5.18
244258241.doc "! od 272

In screen 5.19, we see a cursor blinking in the text area, which is an indication that an SQL
Select statement has to be entered.

Sceen 5.1"

In case you are not conversant with the options, you can click on Query Builder, as we have
done, to arrive at screen 5.20.

Sceen 5.2#

The listbox displays the tables that constitute the Northwind database. Click on Customers,
and then on the Add button. The background area in screen 5.21 changes, to display a box
containing the word 'customers', with a list of felds within it. Since there are no more tables
to select from, we click on the Close button.

244258241.doc "7 od 272
Sceen 5.21

In screen 5.22, the frst three felds are selected. This has been achieved by clicking on the
check box, due to which, the selected feld names get added to the Select statement.

Sceen 5.22

Since we are satisfed with what we have achieved, we click on the OK button.

This takes us to screen 5.23, which displays the Select statement that is generated. The
Select statement shows the three selected felds of CustomerID, Company Name and
ContactName for which data is to be retrieved from the Customers table.

244258241.doc "8 od 272
Sceen 5.23

This is where a wizard really faunts its mettle, since it is easier to select from a list, rather
than to write things out manually. The beauty of SQL is revealed in all its glory, when we
have to work with multiple tables.

When we click on the Next button, the screen 5.24 reveals that the wizard has internally
performed a number of tasks for us. Finally, click on Finish to end the wizard.

Sceen 5.24

As shown in screen 5.25, the screen does not show the object on the Form; instead, it has
two objects, i.e. OleDbDataAdapter1 and OleDbConnection1, which are located at the
bottom of the screen.

244258241.doc "" od 272
Sceen 5.25

This highlights the fact that there are two types of controls.
The frst type is similar to a button, which gets displayed in the Form.
The second type is that of OleDbConnection, which does not have an User Interface,
and which gets placed at the bottom of the Form.

The next object required is a DataSet object, which simply relates to a collection of tables.
The Visual Studio.Net interface has a menu option Data. So, click on Data and select the
option of 'Generate Dataset', as shown in Screen 5.26.

Sceen 5.2!

This generates a screen, as shown in screen 5.27.

244258241.doc 1## od 272
Sceen 5.27

We are contented with the default options assigned to our dataset, where the name indicated
is DataSet1. The framework is extremely astute, and hence, it adds the Customers table to
the Dataset, as shown in the screen. Finally, since the check box at the bottom is selected,
the dataset gets added to the Designer.

When the OK button is clicked, the dataset DataSet1 will be displayed at the bottom of the
non User Interface controls. This is shown in Screen 5.28

Sceen 5.28

Next, a DataGrid has to be added to the Form. So, we click on the Windows Form Tab in the
toolbox, select DataGrid and drag it onto the Form window. This is shown in Screen 5.29
and Screen 5.30.

244258241.doc 1#1 od 272
Sceen 5.2"

Sceen 5.3#

The DataGrid and Form are disconcertingly cramped. So, we click on their edges and drag
them diagonally to enlarge their sizes, as in evident in screen 5.31.

244258241.doc 1#2 od 272
Sceen 5.31

Our program had initialized various properties such as ClientSize, Background color etc. To
modify these properties, click on the menu option of View-Properties Window.

Sceen 5.32

This brings up the Properties window on the right hand side of the screen. Since the
DataGrid control is selected, the properties related to the Grid are displayed. When you
select the Form, its properties get displayed in the Properties Window.

Click on the drop down listbox for the DataSource property. It displays a list containing two
items, as seen in screen 5.33. Select the option of DataSet1, as shown in screen 5.34.

244258241.doc 1#3 od 272
Sceen 5.33

Sceen 5.34

The DataMember property that is positioned immediately above the DataSource, is also
required to be Set. So, click on the down arrow, and from the list, select the table named
Customers.

244258241.doc 1#4 od 272
Sceen 5.35

In screen 5.36, we have selected the Customers table. On doing so, the DataGrid
automatically gets transformed to display three felds in the table.

Sceen 5.3!

Now, incorporate another button control into the Form, as is shown in screen 5.37. The
Properties window exhibits the properties for the button, since it is the selected object.

244258241.doc 1#5 od 272
Sceen 5.37

In the Properties window, enter the word 'Load' in the Text property of the button. Then,
press Enter, and you will instantly witness the text on the button change to 'Load', as shown
in screen 5.38.

Sceen 5.38

Now, double click on the button, and enter the following line at the cursor position:

Ale2b2ata9da0ter1./ill(2ataSet11)

244258241.doc 1#! od 272
Sceen 5.3"

In order to verify whether everything has been entered accurately or not, click on the menu
option Debug, and then, click on Start. The screen that emerges is shown in screen 5.40.

Sceen 5.4#

An empty DataGrid and a button labeled 'Load' are displayed. Now, click on the button. Lo &
behold! The screen transforms, displaying the Data Grid containing the data retrieved from
the Customer table, as is evident in screen 5.41.

244258241.doc 1#7 od 272
Sceen 5.41

Let us now snoop behind the scenes to check on the activities that have taken place. We
would be explaining each new step incorporated above, by interpreting the code that has
been generated. You will never be able to grasp the applications without learning the
language. Therefore, we insist that you learn the language before diving straight into the
depths of the applications. We have copied the generated code and presented it below

We have converged our attention around the code that has been introduced recently, so that
our explanation is confned to the newly added code only, in order to avoid repetition.
Furthermore, once the code has been explicated, it will not be exhibited again.

Since the process of code generation has been automated, a lot of code has been included to
handle situations that may possibly occur only once in a million years! Thus, a lot of
redundant code is generated. We have displaced all comments, since they impede our
understanding of the code. We have also done away with all the blank lines, since they
occupy too much space.
8ubli. Class /orm1
6n#erits System.Windo4s./orms./orm
G:e$ion " Windo4s /orm 2esi$ner $enerated .ode "
8ubli. Sub 3e4()
My;ase.3e4()
6nitializeCom0onent()
End Sub
8rote.ted Averloads Averrides Sub 2is0ose(;y<al dis0osin$ 9s ;oolean)
6+ dis0osin$ -#en
6+ 3ot (.om0onents 6s 3ot#in$) -#en
.om0onents.2is0ose()
End 6+
End 6+
My;ase.2is0ose(dis0osin$)
End Sub
/riend Wit#Events Ale2b2ata9da0ter1 9s System.2ata.Ale2b.Ale2b2ata9da0ter
/riend Wit#Events Ale2bSele.tCommand1 9s System.2ata.Ale2b.Ale2bCommand
/riend Wit#Events Ale2b6nsertCommand1 9s System.2ata.Ale2b.Ale2bCommand
/riend Wit#Events Ale2bN0dateCommand1 9s System.2ata.Ale2b.Ale2bCommand
/riend Wit#Events Ale2b2eleteCommand1 9s System.2ata.Ale2b.Ale2bCommand
/riend Wit#Events Ale2bConne.tion1 9s System.2ata.Ale2b.Ale2bConne.tion
244258241.doc 1#8 od 272
8rivate .om0onents 9s System.Com0onentModel.6Container
*System.2ia$nosti.s.2ebu$$erSte0-#rou$#()) 8rivate Sub 6nitializeCom0onent()
Me.Ale2b2ata9da0ter1 3e4 System.2ata.Ale2b.Ale2b2ata9da0ter()
Me.Ale2bSele.tCommand1 3e4 System.2ata.Ale2b.Ale2bCommand()
Me.Ale2b6nsertCommand1 3e4 System.2ata.Ale2b.Ale2bCommand()
Me.Ale2bN0dateCommand1 3e4 System.2ata.Ale2b.Ale2bCommand()
Me.Ale2b2eleteCommand1 3e4 System.2ata.Ale2b.Ale2bCommand()
Me.Ale2bConne.tion1 3e4 System.2ata.Ale2b.Ale2bConne.tion()
Me.Ale2b2ata9da0ter1.2eleteCommand Me.Ale2b2eleteCommand1
Me.Ale2b2ata9da0ter1.6nsertCommand Me.Ale2b6nsertCommand1
Me.Ale2b2ata9da0ter1.Sele.tCommand Me.Ale2bSele.tCommand1
Me.Ale2b2ata9da0ter1.-ableMa00in$s.9dd:an$e(3e4
System.2ata.Common.2ata-ableMa00in$() &3e4
System.2ata.Common.2ata-ableMa00in$("-able"% "Customers"% 3e4
System.2ata.Common.2ataColumnMa00in$() &3e4
System.2ata.Common.2ataColumnMa00in$("Customer62"% "Customer62")% 3e4
System.2ata.Common.2ataColumnMa00in$("Com0any3ame"% "Com0any3ame")% 3e4
System.2ata.Common.2ataColumnMa00in$("Conta.t3ame"% "Conta.t3ame")')')
Me.Ale2b2ata9da0ter1.N0dateCommand Me.Ale2bN0dateCommand1
Me.Ale2bSele.tCommand1.Command-e7t "SELEC- Customer62% Com0any3ame%
Conta.t3ame /:AM Customers"
Me.Ale2bSele.tCommand1.Conne.tion Me.Ale2bConne.tion1
Me.Ale2b6nsertCommand1.Command-e7t "63SE:- 63-A Customers(Customer62%
Com0any3ame% Conta.t3ame) <9LNES (O% O% O)L SEL" & F
"EC- Customer62% Com0any3ame% Conta.t3ame /:AM Customers WHE:E (Customer62 O)"
Me.Ale2b6nsertCommand1.Conne.tion Me.Ale2bConne.tion1
Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Customer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))
Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Com0any3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% =0% "Com0any3ame"))
Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Conta.t3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% "Conta.t3ame"))
Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Sele.tFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))
Me.Ale2bN0dateCommand1.Command-e7t "N829-E Customers SE- Customer62 O%
Com0any3ame O% Conta.t3ame O WHE:E (Cust" & F
"omer62 O) 932 (Com0any3ame O) 932 (Conta.t3ame O A: O 6S 3NLL 932 Conta.t3" & F
"ame 6S 3NLL)L SELEC- Customer62% Com0any3ame% Conta.t3ame /:AM Customers WHE:E
(" & F
"Customer62 O)"
Me.Ale2bN0dateCommand1.Conne.tion Me.Ale2bConne.tion1
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Customer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Com0any3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% =0% "Com0any3ame"))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Conta.t3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% "Conta.t3ame"))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Customer62"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
244258241.doc 1#" od 272
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFCom0any3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% =0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Com0any3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFConta.t3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Conta.t3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFConta.t3ame1"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Conta.t3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Sele.tFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))
Me.Ale2b2eleteCommand1.Command-e7t "2ELE-E /:AM Customers WHE:E (Customer62
O) 932 (Com0any3ame O) 932 (Conta.t3a" & F
"me O A: O 6S 3NLL 932 Conta.t3ame 6S 3NLL)"
Me.Ale2b2eleteCommand1.Conne.tion Me.Ale2bConne.tion1
Me.Ale2b2eleteCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Customer62"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2b2eleteCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFCom0any3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% =0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Com0any3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2b2eleteCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFConta.t3ame"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Conta.t3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2b2eleteCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFConta.t3ame1"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% (0% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Conta.t3ame"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))
Me.Ale2bConne.tion1.Conne.tionStrin$ "8roviderSPLALE2;.1L8ersist Se.urity
6n+o/alseLNser 62saL6nitial Catalo$3ort#4" & F
"indLNse 8ro.edure +or 8re0are1L9uto -ranslate-rueL8a.5et Size=0?HLWor5station" & F
" 62<MNQH6LNse En.ry0tion +or 2ata/alseL-a$ 4it# .olumn .ollation 4#en 0oss" & F
"ible/alse"
Me.9utoS.ale;aseSize 3e4 System.2ra4in$.Size(,% 1()
Me.ClientSize 3e4 System.2ra4in$.Size(!?!% !I()
Me.3ame "/orm1"
Me.-e7t "/orm1"
End Sub
GEnd :e$ion
End Class

In the Form, we frst introduced an OleDbDataAdapter object. This resulted in the creation
of the DataAdapter and DataConnection objects, which carried the information essential to
connect to the database server. Resultantly, the above code was generated.
244258241.doc 11# od 272

Other than calling the InitializeComponent function, the constructor has no other role to
play. All the valuable code is placed in the InitializeComponent function. The Dispose
function remains unchanged, and can be ignored completely. Normally, all the instance
variables are positioned after these housekeeping functions.

We had earlier learnt that two objects of type SqlConnection and SqlDataAdapter were
required to connect to any database in SQL Server. Since these objects are restricted to SQL
Server, they cannot be used in the context of other database servers.

Thus, the code is not generic in nature. Therefore, the Wizard creates objects of type
OleDbConnection and OleDbDataAdapter, since they can then be implemented on multiple
database servers, including SQL Server. Barring this diference, both the objects work in a
similar manner.

Every corresponding object has a number appended to the name of the class. This number
gets incremented when another object of the same kind is added to the Form. This helps in
assigning unique names to each object.


The wizard generates SQL statements for adding, updating and deleting records from the
database. The OleDbCommand object is created for this purpose, since it is conversant in
dealing with SQL.

In the InitializeComponent function, all the instance variables are initialized using the new
keyword with the constructor that does not take any parameters.

The DeleteCommand is a property of type OleDbCommand, which represents an SQL
statement or a stored procedure employed for deleting records. Similarly, the object also
contains properties to represent Insert, Select and Update commands.

The property of TableMappings is of type DataTableMappingCollection. It is a collection
objects that provides the master mapping between the source table and a DataTable. The
AddRange function accepts an array of DataTableMapping objects.

Me.Ale2b2ata9da0ter1.-ableMa00in$s.9dd:an$e(3e4
System.2ata.Common.2ata-ableMa00in$() &3e4
System.2ata.Common.2ata-ableMa00in$("-able"% "Customers"% 3e4
System.2ata.Common.2ataColumnMa00in$() &3e4
System.2ata.Common.2ataColumnMa00in$("Customer62"% "Customer62")% 3e4
System.2ata.Common.2ataColumnMa00in$("Com0any3ame"% "Com0any3ame")% 3e4
System.2ata.Common.2ataColumnMa00in$("Conta.t3ame"% "Conta.t3ame")')')

The frst parameter to the constructor of a DataTable Mapping is a string that represents a
table. The second parameter is the name of the table selected in the Select statement, i.e.
Customers. Following this array, there is another array named Columns, which is a
DataColumnMapping collection.

The DataColumnMapping object takes two strings:
The frst is the column name from the data source.
The second is the column name from the DataSet that it must map to.

244258241.doc 111 od 272
While building the query, we had chosen three columns. Therefore, there are three members
in the array. The parameter names and the column names have been kept identical.

Me.Ale2bSele.tCommand1.Command-e7t "SELEC- Customer62% Com0any3ame%
Conta.t3ame /:AM Customers"

Do bear in mind that most of the above code is superfuous, and hence, dispensable. The
OleDbCommand has a property called CommandText, using which, the
OleDBSelectCommand is initialized to the SQL statement associated with the Command
object. The SQL statement that is generated with the Query Builder, is assigned to this
property.

Me.Ale2bSele.tCommand1.Conne.tion Me.Ale2bConne.tion1

Every Adapter object needs a Connection handle. Therefore, the Connection property is set
to the OleDbConnection object.

The CommandText property in the Insert Object is set to a SQL Insert statement. We can
very easily add records while the DataGrid is displaying its set of records.

Me.Ale2b6nsertCommand1.Command-e7t "63SE:- 63-A Customers(Customer62%
Com0any3ame% Conta.t3ame) <9LNES (O% O% O)L SEL" & F
"EC- Customer62% Com0any3ame% Conta.t3ame /:AM Customers WHE:E (Customer62 O)"

Note, that the syntax for the Insert statement starts with the reserved words 'Insert into',
followed by the name of the table, i.e. Customers, followed by the list of feld names in round
brackets. This is followed by the reserved word 'values', which is followed by the actual
values that need to be inserted, placed within round brackets. These values are not known
at this stage. Hence, they are represented by a ? symbol, which represents a parameter or a
place holder. It will be substituted by a value in due course of time.

The SELECT statement with the Insert command identifes a unique customer record. Since
the line is broken on two lines, the word SELECT has the continuation character of &_ in
double quotes.
One line below the insert command is the Parameters Collection object, which keeps track of
all the parameters.

Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Customer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))

To this collection, we add an instance of an OleDbParameter object, whose constructor takes
the following parameters: First is a parameter name, followed by the data type, followed by
the width of the column, and fnally, followed by the name of the source column. The
parameters have been assigned the same names as those of the felds.

Me.Ale2b6nsertCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Sele.tFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% "Customer62"))

The parameter that identifes the CustomerID in the where clause is given the name of
Select_CustonerID as shown above.

244258241.doc 112 od 272
Me.Ale2bN0dateCommand1.Command-e7t "N829-E Customers SE- Customer62 O%
Com0any3ame O% Conta.t3ame O WHE:E (C" & F
"ustomer62 O) 932 (Com0any3ame O) 932 (Conta.t3ame O A: O 6S 3NLL 932 Conta.t3"
& F
"ame 6S 3NLL)L SELEC- Customer62% Com0any3ame% Conta.t3ame /:AM Customers WHE:E
(" & F
"Customer62 O)"

The Update command follows next, which contains the word Update, followed by the table
name Customers, and fnally, followed by the felds that are to be changed.

Only three of the felds have been chosen. Therefore, the SET command has exactly three
feld names as three parameters. By default, the Update statement acts on all records.
Therefore, to modify only specifc records, the 'where' clause has to be used, thereby
restricting access to the number of records it can act upon.
The CustomerID is the primary key, which has a unique value for each record. Therefore, if
the Primary key is used in the 'where' clause, it will afect only one record.

Me.Ale2bN0dateCommand1.8arameters.9dd(3e4
System.2ata.Ale2b.Ale2b8arameter("Ari$inalFCustomer62"%
System.2ata.Ale2b.Ale2b-y0e.<arWC#ar% ,% System.2ata.8arameter2ire.tion.6n0ut% /alse%
C-y0e(0% ;yte)% C-y0e(0% ;yte)% "Customer62"% System.2ata.2ata:o4<ersion.Ari$inal%
3ot#in$))

If you notice the parameter statement, the name of the feld has been prefxed with the word
Original_. The fourth parameter is an enum of ParameterDirection, which refers to the type
of parameter. The enum consists of the four values of Input, Input Output, Output and
Return Value.

The value of Input signifes that the value has not been received, but would be furnished in
due course. The next value of False is a Boolean, which indicates whether the column will
accept null values or not; a value of True signifes it that it will.

The next value is for precision, which determines the number of digits permissible to the left
and right of the decimal point. This is followed by the Scale parameter, which determines the
total number of decimal places that the feld can be resolved to. Initially the above two
parameters would appear absurd.

Next, we encounter the real column name, followed by a DataRowVersion enum, which takes
four values: Current, Default, Original and Proposed. Original represents original values, as
against the current values. Finally, we come to an object, which currently has no value.

Me.Ale2b2eleteCommand1.Command-e7t "2ELE-E /:AM Customers WHE:E (Customer62
O) 932 (Com0any3ame O) 932 (Conta.t3ame O A: O 6S 3NLL 932 Conta.t3ame 6S 3NLL)"

After the Update command, we shall tackle the Delete command. This command starts with
the words 'delete from', followed by the table name Customers, and then, followed by the
'where' clause that identifes the records that can be deleted. The parameters are identical to
the Update command.

Me.Ale2bConne.tion1.Conne.tionStrin$ "8roviderSPLALE2;.1L8ersist Se.urity
6n+o/alseLNser 62saL6nitial Catalo$3ort#4" & F
"indLNse 8ro.edure +or 8re0are1L9uto -ranslate-rueL8a.5et Size=0?HLWor5station" & F
244258241.doc 113 od 272
" 62<MNQH6LNse En.ry0tion +or 2ata/alseL-a$ 4it# .olumn .ollation 4#en 0oss" & F
"ible/alse"

Now, the focus once again shifts to the OleDbConnection object. Earlier, we had passed the
connection string to the constructor. However, as an alternative approach, we could use the
ConenctionString property instead. This is what the Constructor eventually does with the
string that is passed to it.

We shall restrict ourselves to only a few of the connection string properties for the moment.
When the property Provider refers to the database, a connection gets established. The User
ID property is the username, and the Initial Catalog is Northwind. The rest of the code is
conventional and mundane.

Before concluding its tasks, the wizard takes all the information that has been entered in
the textboxes, and it generates the above code. After the wizard generated the SQL
statements, we clicked on the menu-option Generate Dataset under Data.

/riend Wit#Events 2ataSet11 9s t1.2ataSet1

The dataset name DataSet1, which is the default name, is used to identify the dataset. This
results in the generation of an instance variable called DataSet11 of type t1. Its name is
formed by joining the name of our project with the name of the dataset, i.e. DataSet1.

Before proceeding any further, click on the menu option View, and then, on the Solution
Explorer. This brings us to screen 5.42, which has a window that lists the fles constituting
our project.

Sceen 5.42

A Solution or a project for the moment will be used interchangeably.

The fle Form1.vb contains the code for the Form Design. Double click on the DataSet1.xsd
fle, which is generated on creation of the DataSet object. This brings us to the screen 5.43,
where the relationship has been depicted in a visual form.

244258241.doc 114 od 272
Sceen 5.43

In the Solution Explorer, right click on Form1.vb item. The popup menu that emerges is
shown in screen 5.44. It reveals the options that are available on this item.

Sceen 5.44

On selecting View Code, we arrive at the Code Generator. The other route to reach the Code
Generator is by clicking on the flename Form1.vb on the panel, just below the toolbars.

In the code that is generated within Form1.vb, we place the cursor on the line DataSet11 at
t1.DataSet1, and then, right click on it. Select the option of 'Go to defnitions', as shown in
screen 5.45.

244258241.doc 115 od 272
Sceen 5.45

This option would transport you to screen 5.46, where the class of DataSet1 is defned. It
divulges the fact that DataSet1 is defned in a separate class of DataSet1.vb, and it is
derived from the class DataSet.

Sceen 5.4!

In the beginning of the fle DataSet1.vb, we come across the word Autogenerated, which
merely informs us that a program has generated this fle. Someday we intend to lift the veil
of the name of the program that generates this code, and also the code that it generates.
However, at this moment, we are not interested in the code that is written for the DataSet,
since we shall not be using any of it.

The Visual Basic.Net language assimilates various types of code, which we shall abstain
from analyzing right now. However, we shall explicate the various types of code, as we
stumble upon them in due course.

244258241.doc 11! od 272
In addition to the instance variable that gets created, the following lines get added to the
Form.vb code, when the Generate DataSet menu-option is selected.

Me.2ataSet11 3e4 t1.2ataSet1()
C-y0e(Me.2ataSet11% System.Com0onentModel.6Su00ort6nitialize). ;e$in6nit()
Me.2ataSet11.2ataSet3ame "2ataSet1"
Me.2ataSet11.Lo.ale 3e4 System.Jlobalization.Culture6n+o("enRNS")
Me.2ataSet11.3ames0a.e "#tt0CSS444.tem0uri.or$S2ataSet1.7sd"
C-y0e(Me.2ataSet11% System.Com0onentModel.6Su00ort6nitialize).End6nit()

The frst line simply creates an instance of a DataSet1 object and stores it in DataSet11. The
next line begins with a function called Ctype.

The sole task of the Ctype function is to convert the data type of the frst parameter, to the
data type specifed by the second parameter. Thus, the frst parameter, i.e. DataSet11 object
of type DataSet is converted into the ISupportInitialize type, which belongs to the
System.ComponentModel namespace.

The resultant object is an ISupportInitialize type, from which the BeginInit function is
called. The above line could have been alternately worded as: DataSet11.BeginInit(). This is
so because the DataSet class is derived from ISupportInitialize.

The BeginInit function signals to the framework that the DataSet initialization process has
commenced, and hence, it should stop all activities related to the DataSet, until the EndInit
function gets called. Therefore, the DataSet object is not authorized to carry out any internal
initializations, since these functions optimize changes to multiple sets of properties.

However, at design time, we can co-initialize properties that are contingent upon each other.
For example, the DataSetName specifes a name for the DataSet, and the locale always deals
with the language issues. The namespace property handles the reading and writing of XML
Schemas. A point to be noted here is that, the above code is spread out in the sub
InitializeComponent.


After the DataSet generation is completed, we had selected the DataGrid control from the
Forms Toolbox. This results in the creation of an instance variable called DataGrid1.

/riend Wit#Events 2ataJrid1 9s System.Windo4s./orms.2ataJrid
Me.2ataJrid1 3e4 System.Windo4s./orms.2ataJrid()

C-y0e(Me.2ataJrid1%System.Com0onentModel.6Su00ort6nitialize). ;e$in6nit()

Me.2ataJrid1.2ataMember ""
Me.2ataJrid1.Header/oreColor System.2ra4in$.SystemColors.Control-e7t
Me.2ataJrid1.Lo.ation 3e4 System.2ra4in$.8oint((!% H=)
Me.2ataJrid1.3ame "2ataJrid1"
Me.2ataJrid1.-ab6nde7 0

Me.Controls.9dd:an$e(3e4 System.Windo4s./orms.Control() &Me.2ataJrid1')
C-y0e(Me.2ataJrid1% System.Com0onentModel.6Su00ort6nitialize).End6nit()

In general, ushering in of any control leads to the generation of additional code in the above
format. An instance variable is created with the name of the class, followed by a number
beginning with 1, and not 0.
244258241.doc 117 od 272

It is assumed that every control would be dealing with events. Therefore, it has BeginEvent
and EndEvent methods, which allow the control to be initialized without any interference. In
principle, they serve the purpose of a "Do Not Disturb" sign. The control is at liberty to act
in any way that it likes, until the EndEvent method is called. It even enjoys the license not to
do anything at all !

The abovementioned two methods are actually precautionary measures, which may or may
not be implemented.

The DataMember property is initialized to Null, the HeaderForeColor property is initialized to
a predefned color, the tab index is initialized to 0 and the name is initialized to DataGrid1.
The only important property is Location, since its co-ordinates determine the position on the
Form.

You may wonder as to why Visual Studio.Net provides distinct properties for each control.
The logic behind this is that Visual Studio.Net is oblivious to what is being written, since it
is the job of the control to usher in the code that it yearns for. The AddRange function is
used to add the control to the Controls collection.

When the DataSource property of the DataGrid is set to DataSet, the line given below gets
inserted. It also afects the design time look of the DataGrid by displaying a plus sign.

Me.2ataJrid1.2ataSour.e Me.2ataSet11

Each time a property is altered, an additional line of code gets added to the Code Painter.
Thus, the DataSource property gets set to DataSet11.

Our view-point is that, every software developer should use Visual Studio.Net, since it is
sure to make each one of them more efcient programmers.

The diferent user interfaces of the Properties editor also ensure that, on most occasions,
the user does not have to enter a value. This is achieved by providing drop down listboxes
encompassing the various possible values, thereby eliminating the slightest probability of
the user committing a blunder.

Yet another advantage is that, very often, programming tends to become very tedious and
irksome. Therefore, it is a dream come true when the framework generates the code for us,
even if it does so only once in a while.

Next, the DataMember property is set to Customers. This does not add any fresh line of
code, but merely changes the previously written line to the following:
Me.2ataJrid1.2ataMember "Customers"

We would defnitely want you to attempt a small experiment. In the Design Mode, Set the
DataSource property to None. On doing so, the DataMember property too gets reset to None,
thus echoing the above action.

Visual Studio.Net transmutes itself into a feature of convenience, whereby, the dynamic
behaviour gets refected by the code in the control itself, such as a DataGrid control. Next,
we insert the button control. This leads to the addition of the following code in the fle:

244258241.doc 118 od 272
/riend Wit#Events ;utton1 9s System.Windo4s./orms.;utton
Me.;utton1 3e4 System.Windo4s./orms.;utton()
Me.;utton1.Lo.ation 3e4 System.2ra4in$.8oint(?H% 1>=)
Me.;utton1.3ame ";utton1"
Me.;utton1.-ab6nde7 1
Me.;utton1.-e7t ";utton1"

As can be seen above, the outcome is very predictable when the code is generated by a
computer program. An instance variable Button1 is created, which can also handle events.

In the InitializeComponent function, the instance variable is actually instantiated, and the
properties of Location, Name, TabIndex and Text properties are set. The TabIndex property is
set to 1, since it is the second control that is being added.

Me.Controls.9dd:an$e(3e4 System.Windo4s./orms.Control() &Me.;utton1% Me.2ataJrid1')

The utility of the AddRange function is demonstrated beyond doubt, when controls get
added to the Form. Note, that by using an array, the Button and the DataGrid are added
concurrently.

When the Text property of the button is changed to 'Load', the following line gets added:

Me.;utton1.-e7t "Load"

We have decided to refrain from explaining the same code repetitively. The above can be
achieved by double clicking on the button and writing the code that is shown above. We are
nearing a state of considerable ease while working with Visual Studio.Net, since we are now
in a position to unravel as to what is happening internally.

The next application that we have chosen to build is that of a Master-Detail, or a Parent-
Child, or a One-To-Many relationship, using Visual Studio.Net. Firstly, we intend to display a
list of Customers in our data grid, and then, we wish to display the orders placed by each
customer.

So, watch out! Here we go!

Click on the menu-option, File-New-Project. Now, you shall arrive at the New Project dialog
box. As usual, in the frst pane, select the option of Visual Basic projects, and in the second
pane, select the option of Windows Applications. The name assigned to this project is t3,
and the project shall dwell in the directory v1. Then, click on the OK button.

The New Projects dialog box retains information about the projects that were last worked
upon. Hence, on many occasions, the previous values remain selected.

Thereafter, we select the DataAdapter control after clicking on the Data Tab in the ToolBox.
The wizard begins in the same way as before, i.e. by asking for information that it requires to
generate the code.

The screen 5.47 depicts the previous connection that we had made to the Northwind
database.

244258241.doc 11" od 272
Sceen 5.47

And if it does not do so, click on the drop down listbox, which will display a list of
connections that have been created previously. So far, we have created only a single
connection, thereby rendering this list inconsequential as of now.

Ensure that the Northwind connection is selected, and then, click on the Next button. In the
screen for data retrieval, the default option of 'SQL statement' is left selected, since we are
not yet well versed in working with 'stored procedures'. Now, we click on the 'Next' button to
arrive at the screen where we have to enter the SQL statements. We could have used the
Query Builder again, but this time around, we would rather enter the following SQL
statement manually:

SELEC- Customer62% Com0any3ame% Conta.t3ame% Conta.t-itle% 9ddress% City /:AM
Customers

Click on Finish to create the Connection and Adapter objects, which represent the
connection to the Customers table.

Now, we have to ferret data from the Orders tables. The same process is repeated, using
which, one more OleDbDataAdapter object is dragged onto the Form. The connection is once
again established with the Northwind database, as it contains both the tables of Customers
and Orders.

In the next screen, the data access method option of 'SQL Statement' is left selected. When
we click on the Next button, we are asked for the SQL statement. Here, we manually enter
the following SQL statement:

SELEC- Arder62% Customer62% Em0loyee62% Arder2ate% S#i0Country% S#i0:e$ion% S#i0City
/:AM Arders

To proceed further, click on the Finish button.

From the Orders table, we have randomly chosen some felds, keeping in mind that the
CustomerID feld is of primary importance, since it is the only link between the two tables of
244258241.doc 12# od 272
Customers and Orders. It is not mandatory for the Primary key and Foreign key to possess
the same name. However, both of them must be specifed in the list of felds of the Select
statement. The outcome of this activity is the creation of a single control named
OleDbDataAdapter2. This is shown in screen 5.48.

Sceen 5.48

The framework is extremely smart. It realizes that an attempt is being made to re-establish a
connection to the Northwind database. Therefore, it reuses the existing connection, instead
of creating a new one.

The Data is to be displayed in a control. So, at this juncture, instead of using the DataGrid,
a listbox from the Windows Form tab in the toolbox is used.

Bring in the listbox control, and then, click on Generate DataSet in the Data menu. The
dialog box that gets displayed, has a dataset name that we are quite content with, but the
Customers table is not shown as selected.

244258241.doc 121 od 272
Sceen 5.4"

Select Customers, as shown in screen 5.49, and then, click on OK. This results in the
addition of one more control named DataSet11, to the list of three invisible controls.

Next, we click on View, followed by Solution Explorer, to activate the window. Then, double
click on the fle named dataset1.xsd. This activates the XML Designer, as shown in screen
5.50.

Sceen 5.5#

Here, we come across two tables that constitute our dataset, viz. Customers and Orders.
Each table must necessarily have a Primary key, which is normally a single feld. Thus, we
see two keys listed in front of the felds, which are the primary keys. The second column
indicates the data types of the felds.

The toolbox has only one tab named XML Schemas, from where the last control named
Relation is introduced into the Form. The control is dropped onto the Orders tables, since it
is the Child table. This brings up the Edit Relation dialog box.

244258241.doc 122 od 272
Sceen 5.51

The frst textbox discloses the name of the relation i.e. CustomersOrders, which would be
displayed in the DataGrid. Then, there exist two listboxes, which when clicked upon, exhibit
a list of tables in the dataset of Customers and Orders, respectively.

The Parent table is the Customers table, since it contains unique values for the CustomerID,
and the child table is Orders, which has the Foreign key, encompassing multiple values for
the CustomerID. When we drop the relation object on the child, it picks up most of these
values and sets them as defaults. Hence, we do not have to enter them ourselves.

The dialog box is smart enough to select CustomerID as the Parent key, but it expects us to
select the Foreign key ourselves.

Therefore, we click on the down arrow, as in screen 5.52, and select the CustomerID column
as the Foreign key, and then, we click on OK.

Sceen 5.52
244258241.doc 123 od 272

The visual representation of this relationship is depicted in screen 5.53. The Customer table
has one unique id; and hence, it has a single arrow, whereas the Orders table has many
occurrences of the ids. Hence, CustomerID has multiple arrows leading to it.

Sceen 5.53

Once the relation is set, click on the tab Form1.vb. Then, Drag and Drop a listbox control
from the ToolBox on the form, and move on to the property of DataSource, as shown in
screen 5.54. Set the value of the DataSource property to DataSet11.

Sceen 5.54

The next property of DataMember shows a drop-down listbox, which when clicked on,
displays the two tables of Customers and Orders. This is shown in screen 5.55.

244258241.doc 124 od 272
Sceen 5.55

This occurs because the DataSource property is initialized to the dataset named DataSet11.
The two tables named Customers and Orders, which comprise the dataset object, are visible.

Sceen 5.5!

As we want to select the feld of customer name, we click on the plus sign of the Customers
table. This leads to a display of all the felds specifed in the Select statement.

The company name is a lot more intuitive than the customer id. So, the value of the
property is initialized to Customers.CompanyName, i.e. the name of the table, followed by a
dot, followed by the name of the feld.

In order to authenticate the list, press the F5 key. This compiles and runs the project. The
output is extremely disappointing, since all that we see is an empty listbox, as shown in
screen 5.57.

244258241.doc 125 od 272
Sceen 5.57

Close both, the Form window and the window labeled as Output. In the designer mode, drag
and drop a button from the ToolBox, and change its label to 'Load', as shown in screen
5.58.

Sceen 5.58

Double click on the button, and enter the following code in the event handling function:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Ale2b2ata9da0ter1./ill(2ataSet11)
End Sub

Here, as before, we call the Fill function of the OleDbDataAdapter object from the Customers
table, since presently, we are not interested in the data contained in the Orders table.

244258241.doc 12! od 272
Press F5 to run the application, and then, click on the button labeled 'Load'. This results in
the listbox getting flled with data, as shown in the screen 5.59.

Sceen 5.5"

The Fill function is responsible for flling up the empty dataset, which is eventually displayed
by the control. This is because, the property in the control is set to this dataset. At this
point in time, the data from the Customers table is on display, but there is no sign of data
from the Orders table.

Now, to retrieve data from the Orders table, close the windows that have popped up while
running the program, and drag and drop a DataGrid onto the Form. Change the layout of
the control, as shown in screen 5.60.

Sceen 5.!#

The DataSource property in the DataGrid is set to DataSet11. For the DataMember feld, the
property is set to the name of the Relation object and the table name
Customers.CustomersOrders.

244258241.doc 127 od 272
Sceen 5.!1

Moreover, one line of code is inserted in the event handling code of the button.

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Ale2b2ata9da0ter1./ill(2ataSet11)
Ale2b2ata9da0ter!./ill(2ataSet11)
End Sub

Now, run the above program by pressing the F5 key. When the Form loads on, click on Load.
The screen that appears, looks like the screen 5.62, wherein a list of customer names is
displayed in the listbox, followed by the list of orders in the Orders tables.

Sceen 5.!2

Now, each time that a new customer is selected, the list of orders of that customer is
displayed in the DataGrid. This results from the two changes that we have efected: Firstly,
244258241.doc 128 od 272
we had flled up the Orders table using the Fill function. Secondly, we had used the name of
the relation as a DataMember name.

The DataGrid, on learning that the name specifed is not a table name, uses the relation
object to determine the records that need to be displayed.

Also, while clicking on a new customer name in the listbox, the DataGrid is apprised about
the new Customer that has been selected. Hence, it alters the records displayed in the
DataGrid, depending upon the CustomerID in the Orders table.

Me.2ataJrid1.2ataMember ".ustomers..ustomersorders"

When the DataMember in the datagrid is set to the relation object, the control feld merely
adds one line, to initialize the property to the value. No other code gets inserted.
Furthermore, no DataRelation object gets created in the Form code. It is found in the fle
DataSet1.vb.

The above example appears to be too simplistic. So let us spice things up by adding a little
more complexity. The Orders table summarizes the orders as per the customer id. Moreover,
there exists a table named Order Details, which consists of the list of orders per order id.

What we wish to accomplish at this juncture is, to prepare a list of orders as per the order
id, when a certain order is clicked on. So, to begin with, we need an SQL statement to fetch
records from the Order Details table.

So, from the Data category in the toolbox, the control named OleDbDataAdapter is again
inducted into the Form. Then, we click on the Next button thrice:
Firstly, on the opening screen.
Secondly, on the Connection screen, since the Northwind connection is chosen by
default.
Thirdly, on the screen in which the default of SQL Statement has been chosen.

In the text block, we now have to write the SQL Select statement, which fetches the records
for the specifed felds from the Order Details table. A point to be noted is that, whenever the
name of a table contains a space, the table name must be placed within square brackets.

SELEC- Arder62% 8rodu.t62% Nnit8ri.e% Puantity% 2is.ount /:AM TArder 2etailsU

When we click on Finish, one more OleDbDataAdapter object gets added at the bottom of the
Form.
The DataSet must be regenerated, for which the Generate option is selected from the Data
menu option.

The dialog box that appears contains only the newly added table as selected. But, we need
to select all the three tables, as seen in screen 5.63.

244258241.doc 12" od 272
Sceen 5.!3

Finally, click on OK. In case a message box pops up, click on 'Yes to All'. Now, make sure
that the Solution explorer is visible.

If it is not, then click on the menu View-Solution Explorer, and then, double click on the
DataSet1.xsd fle. As we invariably fall short of screen space, we recommend that you scroll
to the right to arrive at screen 5.64.

Sceen 5.!4

Here, we come across the third table named Order Details. After the table comes into sight,
drop the Relation object onto the Order Details table. Remember that a single order id in the
Orders table will have multiple records of the order id in the Order Details table.

In the Edit Relation dialog box, the name of the relation is shown as
CustomersOrder_x0020_Details. We will not amend it, since the framework automatically
changes it when the names of the Parent table and the Child table change. If you change the
244258241.doc 13# od 272
name of the parent table from Customers to Orders, the name of the relation will change to
OrdersOrder_x0020_Details. If this does not happen, we request you to amend it manually
to OrderssOrder_x0020_Details.

For each order record found in the Orders table, there exists a list of order details in the
Order Details table. Therefore, the child element is assigned to Order Details. However, when
you click on the down arrow of the dropdown listbox, three tables will be displayed. This is
because the DataSet now comprises of three tables. Ensure that the child element contains
the table Order Details. In the Fields block, the Parent key feld is OrderID. Therefore, the
child key feld that is currently empty, is also changed to OrderID.

Make sure that your screen appears similar to what is seen in screen 5.65, and then, click
on OK.

Sceen 5.!5

The screen 5.66, which comes up next, displays a 'one to many relation' between the tables
Orders and Order Details. It is always advisable to periodically refresh everything, as well as
to save all the work. So, click on the menu option File-Save All.

244258241.doc 131 od 272
Sceen 5.!!

In order to verify the fact that the relation object has been inserted, click on the property
called DataMember. The drop down listbox displays a plus sign next to the Orders.

Click on the plus sign to see the relation object as shown in screen 5.67.Thus, the
DataMember exhibits a total of two relations.

Sceen 5.!7

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Ale2b2ata9da0ter1./ill(2ataSet11)
Ale2b2ata9da0ter!./ill(2ataSet11)
Ale2b2ata9da0ter(./ill(2ataSet11)
End Sub

Finally, before the project is executed, the Fill function of the OleDbDataAdapter3 is placed
in the Load button.
244258241.doc 132 od 272

Run the application and click on the button. The screen that comes up is shown in screen
5.68. Here, we witness a list of Orders in the DataGrid, with each of them having a plus sign
placed next to it.

Sceen 5.!8

If you click on the plus sign, the screen 5.69 containing the name of the relation is seen.
Now, click on the relation name. This brings up the screen shown in screen 5.70, where the
order details for a specifc order id are displayed.

Sceen 5.!"

Sceen 5.7#

244258241.doc 133 od 272
Now, we present one more database application. In this example, we wish to display one
record at a time.

Click on the menu File-New-Project, and in the New Project dialog box, select the option of
Visual Basic projects in the frst pane, and the option of Windows Application in the second
pane. Name the project as t4, and then, click on OK.

Usher in the OleDbDataAdapter object from the Data tab in the toolbox. This object is
brought in to enable us to insert an SQL select statement, which would retrieve data from
the database. Click on the Next button on the frst three screens, and in the SQL statement
textbox, enter the following Select statement:

SELEC- Com0any3ame% Conta.t3ame% Conta.t-itle /:AM Customers

Since we are running short of time and space, we shall display only three felds from the
Customers table. On clicking the Finish button, the two objects of Adapter and Connection
object get created. Then, we generate the DataSet object, by selecting the menu option of
Generate DataSet from the Data menu. All the default settings are acceptable to us.
Therefore, we click on OK, resulting in the creation of a DataSet called DataSet1.

In this application, we want to display the data that has been retrieved from the database in
textboxes. So, three textboxes from the toolbox are dragged onto the Form. This is shown in
screen 5.71. These three textboxes are named as TextBox1, TextBox2 and TextBox3.

Sceen 5.71

Now, make sure that the frst textbox is selected. Scroll down the Properties window, until
the Data section property come into sight.

Then, click on the plus sign of DataBindings, as shown in screen 5.72. The main purpose of
this action is to set the Text property to a feld in the database. The Text property of the
textbox has a drop-down listbox, which when clicked on, shows DataSet11, which is the lone
dataset created in the project.

244258241.doc 134 od 272
Sceen 5.72

A point to be considered here is that, we have not added a DataSet to our textbox. In spite of
this, the TextBox is astute enough to display all the DataSet objects that have been created
in the project.

Clicking on the plus sign of the DataSet object, will bring up a list of tables that comprise
the DataSet. Our listing reveals only one table named Customers. Then, we click on the plus
sign in front of Customers, to arrive at a list of felds that make up the table, as shown in
screen 5.73.

Sceen 5.73

Not all the felds from the table are visible, because the SQL Select statement shows the
three selected felds along with the Primary key.

244258241.doc 135 od 272
Sceen 5.74

Select the feld of Company name. Doing so will change the value of the Text Property to
DataSet11 - Customers.CompanyName. The syntax for the value is as follows: The name of
the DataSet, followed by table name, and fnally, followed by the feld name. Thus, a feld
from the table present in a DataSet is now bound to a textbox.

A similar approach is followed for the second textbox named TextBox2.

Here, we click on the textbox TextBox2 and scroll down to DataBindings. From the Drop
down list, which is obtained after clicking on the plus sign of DataSet11 and the Customers
table, we select the third feld named ContactTitle.

For the third textbox, the above procedure is repeated, and the feld named CustomerID is
selected.

Press F5 to run the program. The result of our actions is shown in screen 5.75, where some
default text has already been entered in the textboxes.

244258241.doc 13! od 272
Sceen 5.75

Since this is evidently distinct from what we had anticipated, we close the running
application and efect the requisite amendments.

Select the frst TextBox and scroll down to the Text property. Then, delete the value assigned
to the Text property, as shown in screen 5.76.

Sceen 5.7!

Now, press Enter, and as an outcome of this, the textbox in the Form does not show any text
at all. The same process is reiterated for the other two textboxes.

If you have been sufciently attentive and assiduous, you would have realized that earlier,
the Text property did not contain a database icon, but the moment the Data Binding Text
property is set to a feld, the Text property obtains an icon, indicating the fact that the data
property will overwrite this Text property.

244258241.doc 137 od 272
The designers of the TextBox control should have added one more feature in that, they
should have ensured that the Text property blanks out as soon as the feld is set to a Data
Text property. The main reason that the textboxes do not display any data from the table is
that, the Customers table in the DataSet11 is empty. The Fill function has not been
introduced so far, and hence, it has not been executed.

Now, we introduce a Button by selecting it in the toolbox, and changing the Text to 'Fetch'.
Then, after double clicking on the button, the following code is introduced in the mouse
event handler, using the code painter:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
Ale2b2ata9da0ter1./ill(2ataSet11)
End Sub

Now, when the above program is executed by pressing the F5 key, the screen does not
display any text in the textboxes.

When the button is clicked, the window shows the frst record, as seen in screen 5.77.

Sceen 5.77

It gladdens the heart to see the record values in the textboxes. However, this is not enough,
since we intend to view the subsequent records also. So, close the windows of the running
application and add one more button, which shall facilitate scrolling to the succeeding
records. Change its label to 'Next', as shown in screen 5.78.

244258241.doc 138 od 272
Sceen 5.78

Double click on this button to add the following code to the event-handling sub of
Button2_Click.

8rivate Sub ;utton!FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton!.Cli.5
2im b 9s ;indin$Conte7t
b ;indin$Conte7t
2im bb 9s ;indin$Mana$er;ase
bb b(2ataSet11% ".ustomers")
bb.8osition " 1
End Sub

The class Form has a property called BindingContext, which returns a BindingContext
object. This object is stored in b. The task of a BindingContext object is to attend to all the
BindingManagerBase objects. So, by using b, which is a BindingContext containing the
default property or indexer of the DataSet, and using the table, the BindingManagerBase
object can easily be retrieved.

Every DataSet and table in the DataSet combination has its own BindingManagerBase
object. This BindingManagerBase object takes care of all the Binding objects. The
BindingManagerBase object has a property called Position, which is of type read-write. It
reveals the current active record in the Data Table. A new value can be assigned to it, in
order to make the record active.

Now, Run the project by pressing the F5 key. Then, click on the Fetch button. The frst
record will get displayed. On clicking the Next button, the second record will get displayed,
as shown in screen 5.79. Thus, it is the Position property that establishes the active record.

244258241.doc 13" od 272
Sceen 5.7"

Next, we intend to move backwards amidst the records. So, we repeat the same procedure,
wherein a button is brought into the Form from the toolbox and its label is changed to 'Prev'.
Then, the following lines of code are entered in the event handler function:

8rivate Sub ;utton(FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton(.Cli.5
2im b 9s ;indin$Conte7t
b ;indin$Conte7t
2im bb 9s ;indin$Mana$er;ase
bb b(2ataSet11% ".ustomers")
bb.8osition bb.8osition R 1
End Sub

After pressing the F5 key, we frst click on Fetch, followed by the Next button, which takes us
to the next record. Then, we click on the Prev button, and we are transported back to the
previous record. This is shown in screen 5.80. Thus, we have been able to scroll through a
series of records.

Sceen 5.8#

We would now like to implement the following:
Move to the frst or last record, depending on the button that is clicked.
Display the current record number and the total number of records in the table.

To achieve this, we do the following: One more button is introduced in the Form, and its
label is changed to 'First'. This button is internally assigned the name of 'button4', and the
following code is inserted in it:

8rivate Sub ;utton=FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton=.Cli.5
2im b 9s ;indin$Conte7t
b ;indin$Conte7t
2im bb 9s ;indin$Mana$er;ase
bb b(2ataSet11% ".ustomers")
244258241.doc 14# od 272
bb.8osition 0
End Sub

The only statement that has been modifed in the code above is that of the Position property,
Which is set to 0, and not to 1, since the counting starts from 0.

Press F5 to run the application. First, click on the 'Fetch' button. Then, click on the 'Next'
button twice, to move to the third record. Now, click on the button labeled 'First'. This brings
us back to the frst record.

Close the Form and revert back to Visual Studio.Net. Now, we shall display the current
active record number and the total number of records present in the customer table.

Select the TextBox control and drag and drop it onto the Form. This TextBox is named
textBox4, as shown in screen 5.81.

Sceen 5.81

Delete the default value assigned to the Text property of the TextBox. Then, select the tab
Form1.vb, and at the very bottom, just prior to 'end class', enter the following lines of code
in Sub abc. The moment we press the Enter key for the Sub abc, the words End Sub
automatically get added. This is evident from screen 5.82.

244258241.doc 141 od 272
Sceen 5.82

Sub ab.()
2im . 9s 6nte$er
2im 0 9s 6nte$er
. ;indin$Conte7t(2ataSet11% ".ustomers").Count
0 ;indin$Conte7t(2ataSet11% "Customers").8osition " 1
-e7t;o7=.-e7t ":e.ord 3o " & 0.-oStrin$ & " o+ " & ..-oStrin$
End Sub
We start by creating two variables named c and p, both of type integer. The variable c will
store the number of records in the table, and p will store the current record position.

The BindingManagerBase object possesses a Position property for the current record
number, and a Count property for the total number of records that the table contains. The
variables c and p are initialized to the values returned by these properties, respectively.

An alternative approach would be to split up the above statement.

Firstly, the BindingContext property, which returns a BindingContext object, can be stored
in a variable. Then, an indexer that takes two strings, can be used to return a
BindingManagerBase object. Finally, the Count property of this object is furnished to
determine the total number of records in the table. We leave it to you to determine as to
which of these two approaches is simpler to comprehend.

We fnally initialize the Text property to the string that results from displaying the variables
c and p. To write it all on a single line, the & sign is used, which acts like a delimiter while
concatenating strings. Before we can see the output, there is one more task to be performed.
The last objective is to introduce a button and label it as 'Last'. When this button is clicked
on, the last record should become visible. So, double click on it and enter the following code:

8rivate Sub ;utton,FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton,.Cli.5
;indin$Conte7t(2ataSet11% "Customers").8osition 10000
ab.()
End Sub

244258241.doc 142 od 272
In this sub, the Position property is assigned a value of 10000. We allocated such a
mammoth value, despite being cognizant of the fact that such a large number of records do
not exist. This is because, whenever a very large number is specifed, which goes beyond the
record count, the active record becomes the last record.

The sub abc must be called in each of the four button events, in the manner shown above,
otherwise, the textbox will not be updated.

Another course of action to achieve the above would be to use the Count property, to
ascertain the total number of records, and then, to initialize the Position property to this
value. In efect, the accurate value is the count value minus 1, because the value of record
position for the frst record is 0.

Now, when we click on Fetch, followed by the button labeled as Last, the last record becomes
visible, as shown in screen 5.83.

Sceen 5.83

The textbox gets updated, informing us about the record that is currently active. Again,
since the Position property starts from 0 and not from 1, the value to be displayed frst
needs to be incremented by 1.

This is the last application in the chapter, before we call it a day. What we intend to achieve
through this application is to display those records of customers in the datagrid, which meet
a certain criteria.

Create a new project by choosing the menu option File-New-Project. Then, in the New Project
dialog box, as usual, select Visual Basic projects in the frst pane and Windows Application
in the second pane. The name assigned to this project is t5.

Since the application revolves around fetching data from the Customers table in the
database, the OleDbDataAdapter control is brought in from the toolbox. By this time, you
must have committed all the steps to memory, since this process has been harped upon
throughout this chapter. Everything remains the same, as has been explained earlier, except
for the SQL Select statement, which is as follows:
244258241.doc 143 od 272

SELEC- Customer62% Com0any3ame% Conta.t3ame% Conta.t-itle /:AM Customers 4#ere
(Country O)

The above SQL Select statement will retrieve records from the Customers table, where the
feld Country matches a specifed value. At this instant, the value is not known, hence the ?
symbol is used. The control ignores the new amendment in the syntax, and in its usual
manner, it generates the OleDbDataAdapter object and the OleDbConnection Object.

Now, click on the menu Data, followed by the Generate DataSet. All the values are
acceptable to us. Therefore, we leave everything untouched, and click on OK.

Subsequent to this, initiate a DataGrid control from the Windows Forms category in the
ToolBox into the Form. The DataSource property of this Form is set to DataSet11 and the
DataMember is set to Customers.

Then, bring in a button on the Form, and change its label to 'Fetch'. Then usher in a textbox
named TextBox1. Blank out the value assigned to the text property. The Form should look
like what is shown in screen 5.84.

Sceen 5.84

Double click on the button, and enter the following code:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im . 9s System.2ata.Ale2b.Ale2bCommand
. Ale2b2ata9da0ter1.Sele.tCommand
2im 0 9s System.2ata.Ale2b.Ale2b8arameterColle.tion
0 ..8arameters
2im o 9s System.2ata.Ale2b.Ale2b8arameter
o 0("Country")
o.<alue -e7t;o71.-e7t
2ataSet11.Clear()
Ale2b2ata9da0ter1./ill(2ataSet11) End Sub

244258241.doc 144 od 272
In the above code, the property SelectCommand of the OleDbDataAdapter1 object is used to
retrieve an OleDbCommand object.

This OleDbCommand object, which is present in the System.Data.OleDb namespace,
represents the Select statement entered in the OleDbDataAdapter wizard. It has a property
called 'parameters', which stores all the parameters in the SQL Select statement.

A parameter is a feld in the 'where' clause, which is assigned a value of a ?. The parameters
property returns an OleDbParameterCollection object. Then, using an indexer, the individual
parameters can then be accessed. Since it is a collection object, multiple parameters can be
added to it.

The indexer takes the name of the feld as a string parameter, in order to access the
parameters. It returns an OleDbParameter object, which has a member of Value. This
member is set to a value that relates to the feld Country. This is what the user enters in the
Textbox. Thus, the value of the feld country can be set to whatever the user enters in the
textbox.

At times, the DataGrid may contain certain values from a previous query. Hence, it is a good
idea to Clear the contents of the table Customers. If the Clear function is not used, at times,
the residual data from some earlier query may linger on, thereby cluttering the existing
data.

As usual, the Fill function flls up the dataset with records that match the value of the
Country that the user enters in the textbox.

Press F5 to run the program, and enter the name of the country as "UK". When the Fetch
button is clicked, the output displayed will be the records of customers who reside in UK,
thereby fltering the required records from amongst all the records in the table. This is
shown in screen 5.85.

Sceen 5.85

This is an example of a dynamic query, wherein the user decides the criteria, based on
which, the data is dynamically retrieved and displayed.
244258241.doc 145 od 272

?. HM- and HS6

Let us now focus on XML, which seems to be the order of the day, since every developer
worth his salt seems to be singing this new mantra! Though it is impossible to comprehend
XML in a day, but we still are determined to give it a try.

We start by creating a new project called t6 in the c:\v1 subdirectory. For this, click on the
File-New-Project menu option. Then, select Visual Basic Project in the frst pane, and select
Windows Application in the second pane. Click on OK to generate the smallest possible
Windows application.

Now, to add a new fle to this project, click on File-New, and select the option of File instead
of Project, as shown in screen 6.1.

Sceen !.1

The dialog box that emerges is shown in screen 6.2. It displays a long list of fle types that
can possibly be added to the project.

244258241.doc 14! od 272
Sceen !.2

Normally, most fles that are vital for the project get added automatically. However, we are
still rendered the fexibility of adding more fles, if we so desire. Choose the option of XML
fle and click on Open. This brings up an editor, with a single line written in it, as revealed
in screen 6.3.

Sceen !.3

*O7ml version"1.0" en.odin$"ut+R>" O)

The above stipulated line has to be the very frst line of every XML document. XML stands
for eXtensible Markup Language. It is not a programming language like Visual Basic.Net,
but a language akin to English.

Had we created the fle outside the Visual Studio.Net framework, the above line would have
had to be inserted manually. This is all.

244258241.doc 147 od 272
In future, you hold the prerogative of creating the above fle in any word processor that you
may fancy, since it is absurd to use Visual Studio.Net merely for editing purposes.

Every XML document adheres to certain rules. The frst rule is that the frst line in the
document must begin with <?xml and end with ?>. Any line beginning with <? is known as a
Directive. Rules are meant to be followed, with no questions asked. The second rule is that
the XML directive must have an attribute called version, with a value of 1.0.

An attribute is merely a word that is equated to some value. The value of the attribute
version can only be 1.0, since this is the only valid version of XML in existence. The second
attribute to the XML directive is 'encoding'. This attribute is optional. The value of utf-8
assigned to it signifes that the words that appear in the fle henceforth, belong to the
English language, and not to any other language, such as Chinese, etc.

We now append some more lines as follows:

On the next line, enter the word <customerslist>. Immediately after the 'greater than' sign,
the same word is entered again within angle brackets, but this time with the / sign
preceding it. This is represented in screen 6.4, where we see the following text:

*.ustomerslist)*S.ustomerslist)

Sceen !.4

The code editor can surely read our minds! The rationale behind insertion of the above text
by the code editor is that, any word that begins with an angle bracket, must also end with
an angle bracket.

The words enclosed within angle brackets are called 'tags'. Thus, customerslist is a tag.
Every start tag must have an end tag. An end tag is similar to the start tag, except that it
has the / sign placed before the tag name. The editor is smart enough to generate the end
tag for us.

244258241.doc 148 od 272
The frst tag that is encountered in the XML fle is called the root tag. All other tags must be
placed within this tag. The root tag is mandatory. It can be assigned any name, since there
are no rules in XML governing this aspect.

We have created the XML fle to store a list of two customers. The basic information supplied
for each customer is the name and the phone number. You have to enter the additional
lines, so that the XML fle fnally represents the text given below in the specifed format.

*O7ml version"1.0" en.odin$"ut+R>" O)
*.ustomerslist)
*.ust)
*name)<ijay Mu5#i*Sname)
*0#one)=?H=((?*S0#one)
*S.ust)
*.ust)
*name)Sonal*Sname)
*0#one)=?H=((>*S0#one)
*S.ust)
*S.ustomerslist)

The details regarding each customer are enclosed within the tags of cust and /cust.
Moreover, within the cust tags, there exist two child tags called name and phone, both of
which follow the same rules.

Remember that the end tags get inserted automatically in the XML Editor. To save this fle,
click on 'File- Save XMLFIle1 As' menu option. This is shown in screen 6.5.

Sceen !.5

This brings us to a dialog box as shown in screen 6.6, where we change the sub directory to
point to the root directory, and name the XML fle as yyy. This results in the above XML fle
being saved as yyy.xml in the root directory.

244258241.doc 14" od 272
Sceen !.!

An alternate approach to achieve the above would be to simply fre up a word processor,
enter the above lines manually, and then, save it in a fle named yyy.xml.

Once the fle has been created, bring in a DataGrid control, followed by a button. Then,
double click on the button and enter the following lines of code:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im d 9s 2ataSet
d 3e4 2ataSet("zzz")
d.:eadKml(".CSyyy.7ml")
2ataJrid1.2ataSour.e d
2ataJrid1.2ataMember ".ust"
End Sub

In the above code, a new DataSet object 'd' is created, with the constructor being assigned
the name zzz. Naming the DataSet as zzz is optional. The ReadXml function from the dataset
class is then employed, to populate the DataSet object.

This function is furnished with the full path of the above XML fle. The end result is that the
function flls up the dataset with records from a table called Cust. This occurs because the
customer data is enclosed within the cust tag.

The DataSource property of the DataGrid requires a DataSet object. Therefore, it is
initialized to d, which is the freshly created dataset.

There are alternative approaches to performing any task. Similarly, a dataset can also be
populated by fetching data either from a database table, or from a fle on disk. The
DataMember property is set to the cust table in the DataSet.

Press F5 to run the program. Doing so will result in the display of a button labeled Button1
and an empty DataGrid. Click on the button to populate the grid with the two records from
the XML fle, as shown in screen 6.7.

244258241.doc 15# od 272
Sceen !.7

The names of the tags become the feld names. Therefore, two felds are visible, i.e. 'name'
and 'phone'. Further, the details provided for each customer are represented as records in
the table.

This example illustrates the fact that a dataset can be flled up with records from an XML
fle, without letting the DataGrid control get a whif of it. The Datagrid couldn't care less
about the origin of the data, as long as it receives a dataset.

The same example can also be re-written, using one of the features in Visual Basic.Net.

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im d 9s 2ataSet
d 3e4 2ataSet("zzz")
d.:eadKml(".CSyyy.7ml")
Wit# 2ataJrid1
.2ataSour.e d
.2ataMember ".ust"
End Wit#
End Sub

Modify the code contained in the button, to the code stipulated above. The output however
remains the same.

The 'With' statement calls for a name. Hence, we have provide the name of the DataGrid
object to it, i.e. DataGrid1. In addition to this, all lines of code upto the 'End With', must
begin with a dot. This approach precludes the need to use the object name, along with its
properties, over and over again. Hence, if you are handling multiple properties of the same
object, enclose them within 'With' and 'End With'.

The above method is often encountered in the samples provided with Visual Studio.Net.
Hence, we decided to implement it here. Finally, it is your prerogative to decide whether you
wish to write the control name every time, or you would rather write it once and place dots
before every property name thereafter.
244258241.doc 151 od 272

Click on the tab yyy.xml, and then, add the following lines of XML to the fle:

*O7ml version"1.0" en.odin$"ut+R>" O)
*.ustomerslist)
*.ust)
*name)<ijay Mu5#i*Sname)
*0#one)=?H=((?*S0#one)
*S.ust)
*0rodu.t)
*0rodu.tid)10*S0rodu.tid)
*0rodu.tname)vijay*S0rodu.tname)
*0ri.e)100*S0ri.e)
*S0rodu.t)
*.ust)
*name)Sonal*Sname)
*0#one)=?H=((>*S0#one)
*S.ust)
*S.ustomerslist)

Then we click on the tab Form1.vb Design, and bring in a textbox called TextBox1. The text
property of the control is also blanked out. Then double click on the button and write out
the following code:

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im d 9s 2ataSet
d 3e4 2ataSet("zzz")
d.:eadKml(".CSyyy.7ml")
Wit# 2ataJrid1
.2ataSour.e d
.2ataMember -e7t;o71.-e7t
End Wit#
End Sub

Other than the modifcation in one of the lines, the rest of the code remains the same. The
DataMember property that was earlier set to cust, is now initialized to the Text property of
the TextBox.

Now, press F5 to run the program. In the textbox, enter the name of the table as Product.
Then, click on the button. The output is depicted in screen 6.8.

244258241.doc 152 od 272
Sceen !.8

In the XML fle, another tag called Product has been added. Thus, the DataSet now contains
two tables, i.e. cust and product. The user can either enter 'cust' or 'product' in the textbox.
Depending on the name assigned to the DataMember property of the DataGrid, data from
the selected table is displayed.

Close the running application. Then, click on the textbox to select it, and press the delete
key. To delete the DataGrid control, use the menu option, i.e. frst select the Datagrid
control, and then, click on the menu option of Edit-Delete.

Now, bring in a new textbox control. The only problem with a textbox is that, even though
you can alter its size, by default it displays only a single line.

To incorporate multiple lines in the textbox, select the control and scroll down to the
property named MultiLine in the properties window. The default value assigned to this
control is False. Click on the drop down listbox, as shown in screen 6.9, and select the value
of True.

244258241.doc 153 od 272
Sceen !."

Since this property now has a value of True, we are allowed to change the vertical height of
the textbox, as shown in screen 6.10.

Sceen !.1#

Double click on the button, and replace the existing event handling code with the code
specifed below.

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im s 9s 3e4 System.6A.Strin$Writer()
2im d 9s 2ataSet
d 3e4 2ataSet("#i")
d.WriteKmlS.#ema(s)
-e7t;o71.-e7t s.-oStrin$
End Sub

244258241.doc 154 od 272
Now, press F5 to run the program. When you click on the button, the textbox displays some
text. This is seen in screen 6.11.

Sceen !.11

The text entered in the textbox is shown below.

*O7ml version"1.0" en.odin$"ut+R1H"O)
*7sCs.#ema id"#i" 7mlns"" 7mlnsC7s"#tt0CSS444.4(.or$S!001SKMLS.#ema"
7mlnsCmsdata"urnCs.#emasRmi.roso+tR.omC7mlRmsdata")
*7sCelement name"#i" msdataC6s2ataSet"true")
*7sC.om0le7-y0e)
*7sC.#oi.e ma7A..urs"unbounded" S)
*S7sC.om0le7-y0e)
*S7sCelement)
*S7sCs.#ema)


In the click event of the button, the Dim statement is used to defne and create an object 's'
as an instance of the StringWriter class, from the System.IO namespace. The StringWriter
class deals with large strings very efectively.

We then create a new DataSet object 'd', and call the function WriteXmlSchema from it. This
function accepts a StringWriter parameter 's' and writes the XML schema to it. The Text
property of the TextBox is then initialized to the ToString function from the TextWriter class.

In the .Net world, all classes normally have a ToString function, which returns the string
representation of any object. In this case, the WriteXmlSchema function writes out the
entire schema, which is then displayed in a String format.

Let us now attempt to understand what an XML schema actually entails.

An XML schema fle is an XML document, and hence, like all XML documents, it starts with
the XML directive statement. The directive statement is followed by the root tag named
'schema'.

244258241.doc 155 od 272
An XML schema has to begin with a tag called 'schema'. However, all and sundry can create
tags such as schema. So, to avoid any mis-match, the tag is prefxed with a namespace
followed by a colon. The schema tag is prefxed with 'xs' and a colon. The name of the prefx
is not very signifcant. What is more important is the attribute xs, which uniquely identifes
the xs namespace, and thus, the schema tag. In this case, the xs namespace prefx points to
the URI http://www.w3.org/2001/XMLSchema.

This fle contains the rules for the elements that belong to the xs namespace. We shall
explain each of these rules, one at a time. The xs namespace prefx belongs to the xmlns
namespace prefx, which is not set to anything. The attribute of 'id' merely identifes the
schema. It is assigned the name of the DataSet, i.e. "hi". This part can be safely ignored for
the time being.

Yet another namespace prefx of 'msdata' is created. Thus, all tags prefaced with msdata
belong to a namespace that is distinct from the tags prefaced with 'xs'. This concept of
namespaces is identical to that of the namespaces in Visual Basic.Net. We utilize this
concept to uniquely identify an entity.

The schema element starts with the element tag, with the name attribute initialized to "hi".
The attribute IsDataSet is set to True, to confrm the representation of the DataSet.

The complexType tag is a child in the element tag. It defnes the type for the element named
"hi". The complexType is followed by a choice element, which permits us to pick out our
choice from amongst the options that it contains. We shall not explain this any further at
this juncture, since there is nothing to choose from.

The maxOccurs attribute decides on the occurrence of the elements that follow. The value of
'Unbounded' indicated that there are no limits. The 'choice' tag is a single tag, as it ends
with a /. The above Schema is incomplete, since there is absolutely no data in the DataSet.

8rivate Sub ;utton1FCli.5(;y<al sender 9s System.Abje.t% ;y<al e 9s System.Event9r$s)
Handles ;utton1.Cli.5
2im s 9s 3e4 System.6A.Strin$Writer()
2im d 9s 2ataSet
d 3e4 2ataSet("#i")
d.:eadKml("CCDyyy.7ml")
d.WriteKmlS.#ema(s)
-e7t;o71.-e7t s.-oStrin$
End Sub

This shortcoming is corrected in the code given above. The only change that has been
augmented is the addition of the ReadXml function. This populates the XML schema with
data from the fle yyy.xml.

Before executing the above program, select the textbox control, and then, scroll down the
property window. Then, change the value for the ScrollBars property from None to Both. As
an outcome of this, if and when the data in the textbox exceeds the horizontal or vertical
boundaries, the system will automatically generate a scrollbar. Press F5 to run the program,
and then, click on the button. The screen 6.12 shows a vertical scrollbar.

244258241.doc 15! od 272
Sceen !.12

The schema fle that is listed in the textbox, is given below.

*O7ml version"1.0" en.odin$"ut+R1H"O)
*7sCs.#ema id".ustomerslist" 7mlns"" 7mlnsC7s"#tt0CSS444.4(.or$S!001SKMLS.#ema"
7mlnsCmsdata"urnCs.#emasRmi.roso+tR.omC7mlRmsdata")
*7sCelement name".ustomerslist" msdataC6s2ataSet"true")
*7sC.om0le7-y0e)
*7sC.#oi.e ma7A..urs"unbounded")
*7sCelement name".ust")
*7sC.om0le7-y0e)
*7sCse1uen.e)
*7sCelement name"name" ty0e"7sCstrin$" minA..urs"0" S)
*7sCelement name"0#one" ty0e"7sCstrin$" minA..urs"0" S)
*S7sCse1uen.e)
*S7sC.om0le7-y0e)
*S7sCelement)
*7sCelement name"0rodu.t")
*7sC.om0le7-y0e)
*7sCse1uen.e)
*7sCelement name"0rodu.tid" ty0e"7sCstrin$" minA..urs"0" S)
*7sCelement name"0rodu.tname" ty0e"7sCstrin$" minA..urs"0" S)
*7sCelement name"0ri.e" ty0e"7sCstrin$" minA..urs"0" S)
*S7sCse1uen.e)
*S7sC.om0le7-y0e)
*S7sCelement)
*S7sC.#oi.e)
*S7sC.om0le7-y0e)
*S7sCelement)
*S7sCs.#ema)

The Schema fle incorporates many new lines. The element no longer uses the name "hi" as
the name of the dataset; instead, it takes the root tag of customerslist specifed in the XML
fle. The complexType contains data that describes itself better.

The 'choice' element contains two element tags, since the DataSet comprises of two tables of
'cust' and 'product'. The maxOccurs attribute specifes that the two tables can occur as
many times as is required. The 'cust' and 'product' tags should be permitted to occur infnite
244258241.doc 157 od 272
number of times, as there is no restriction on the number of records that these tables may
contain.

The next thing of importance is a description of the data structure of these tables,
embodying the feld names, their data types, etc. This is what the XML schema world is all
about. It is used to describe entities, and to ensure that it replaces SQL while the data in
the databases is being defned.

There exists an element called 'cust', followed by the complexType element. A 'sequence
element' basically lists out the order that is to be followed. The 'cust' table has two felds,
viz. name and phone. Therefore, there are two elements representing the two felds.

The type attribute comprises of the data type of the felds, and the minOccurs has a value of
0. This indicates the fact that, for the feld, the minimum number of occurrences is 0, i.e.
the feld is optional. The default value of maxOccurs is 1. Thus, the element need not be
present, but if it is present, it can only occur once. Thereafter, the sequence, the
complexType and the element tags are all closed. The same procedure is then repeated for
the product table.

Although the XML schema gives a description of the data, it actually contains no data at all.
The newer versions of SQL Server have avoided using SQL. Instead, they store data in the
XML format, thus allowing any entity to access this data. The very rationale behind using
schemas is that, they are very expressive and they defne rules, which the data in our XML
fles must follow.

We commence by creating our own XML schema fle, using the Schema Painter provided by
Visual Studio.Net.

As always, create a simple windows application by clicking on File-New-Project menu-option,
and by selecting Visual Basic projects and Windows application, in their respective panes.
Name the project as t7, and store it in the c:\v1 subdirectory.

From here onwards, we do things diferently. We add a new item to our project, but instead
of choosing the New option, we opt for the 'Add New Item' from the File menu, as shown in
screen 6.13.

244258241.doc 158 od 272
Sceen !.13

This brings us to screen 6.14, where the dialog box contains a dozen things. The option that
fascinates us is the XML Schema item. Therefore, we click on it and change its name to
zzz.xsd.

Sceen !.14

Then, we click on Open. This brings up the fle zzz.xsd in the Solution Explorer, and it also
kick starts the Schema Painter, as shown in screen 6.15.

244258241.doc 15" od 272
Sceen !.15

The toolbox also undergoes transformation, displaying a large number of elements that can
be added to the painter. If we click on the XML option given at the bottom, it transports us
to the XML code that gets generated, whenever the schema is changed. The screen 6.16
shows the option.

Sceen !.1!

The XML schema fle that gets created, is shown below:

*O7ml version"1.0" en.odin$"ut+R>" O)
*7sCs.#ema id"zzz" tar$et3ames0a.e"#tt0CSStem0uri.or$Szzz.7sd"
element/orm2e+ault"1uali+ied" 7mlns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsCmstns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsC7s"#tt0CSS444.4(.or$S!001SKMLS.#ema")
*S7sCs.#ema)

244258241.doc 1!# od 272
The fle is very similar to the one we explained earlier. However, it now has some new
attributes added to it.

The attribute targetNamespace contains the location of the elements that do not have a
namespace prefx. The elementFormDefault attribute can take one of the two values of
'qualifed' or 'unqualifed'. The default value is 'unqualifed'. Since the value chosen is
'qualifed', all elements from the target namespaces that are referred to, have to be qualifed
with the namespace prefx.

Had we clung on to the default value, there would have been no need for qualifying the
elements, provided that they belong to the target namespace. In addition to these, yet
another namespace prefx called 'mstns' is created.

We will now switch back to the Schema tab at the bottom, and click on the simpleType
control. A mere click on it does no wonders. The control must be dragged and dropped onto
the form.

Change the name from simpleType1 to 'vijay', and leave the data type string unchanged.
Screen 6.17 exhibits the outcome of our actions.

Sceen !.17

If you are also burning with curiosity as we were, you would click on the word 'string'. This
will display a drop down listbox as seen in screen 6.18.

244258241.doc 1!1 od 272
Sceen !.18

Now, switch over to the XML tab to view some fresh XML code that has been incorporated.

*O7ml version"1.0" en.odin$"ut+R>" O)
*7sCs.#ema id"zzz" tar$et3ameF0a.e"#tt0CSStem0uri.or$Szzz.7sd"
element/orm2e+ault"1uali+ied" 7mlns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsCmstns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsC7s"#tt0CSS444.4(.or$S!001SKMLS.#ema")
*7sCsim0le-y0e name"vijay")
*7sCrestri.tion base"7sCstrin$" S)
*S7sCsim0le-y0e)
*S7sCs.#ema)

Henceforth, only the newly generated sections of the fle would be shown, since we see no
point in repeating the explanation of the schema element, over and over again.

An element is the basic entity for a schema, since it represents a feld or a DataSet. Every
element needs a type. There are basically two types in the schema world, viz. complexType
and simpleType. To represent simple data, a simpleType is used, and to represent complex
data, a complexType is used. The data types of string and integer are built-in types, which
the schema world understands. Hence, for these types, the simple type is used. However, in
the case of user-defned data types, normally the complexType is employed.

'Vijay' is a simpleType. It determines the actual data type of the data that the entity can
represent. Now, since we have specifed 'string', the framework ensures that any element
using the type 'vijay', would only have string values. So, 'vijay' and 'string' do the same job,
and can also be used interchangeably.

Furthermore, the 'restriction' element can be used to specify restrictions on the base type.
So, let us now work towards restricting the types of strings, which can be used with the type
'vijay'. Click on the row below the St word. This would display the varied options that can be
used here. We see only the option of Facet, as seen in screen 6.19.

244258241.doc 1!2 od 272
Sceen !.1"

A Facet is the only option that can be used with simpleType. There are many more options
that can be employed with the complexType.

We then click on the listbox on the right, and arrive at screen 6.20, which displays the
options that are available.

Sceen !.2#

Select the option of 'pattern' and enter '\D{3}' in the textbox on the right, as seen in screen
6.21.

244258241.doc 1!3 od 272
Sceen !.21

Click on the XML tab to see the XML code generated for this action.


*7sCsim0le-y0e name"vijay")
*7sCrestri.tion base"7sCstrin$")
*7sC0attNrn value"D2&('" S)
*S7sCrestri.tion)
*S7sCsim0le-y0e)

We could have written the above XML ourselves, but the Schema Designer makes our life
much simpler. The 'pattern' option gets added as pattUrn, and the value of \D{3} that is
entered, becomes the value of the attribute value. A pattern is a synonym for a regular
expression.

For instance, when the user keys-in a value, the correct characters for the type specifed
must be entered for the element. For example, in an e-mail address, the @ sign must be
inserted at the correct place. People have written volumes on 'regular expressions', which is
worth a perusal in your spare time.

The character \D stands for any Non-Digit characters, and \d stands for a digit from 0 to 9.
The curly braces expect a number, so we have specifed 3 as the number, since we want 3
non-digit characters. Thus, the type 'vijay' is a string, which can have any three non-digit
characters. We may have as many facets as we desire.

244258241.doc 1!4 od 272
Sceen !.22

In screen 6.22, we have three facets, each of which is an enumeration, with the values of
abc, pqr and xyz, respectively. Let us now examine the XML code that is generated.

*7sCsim0le-y0e name"vijay")
*7sCrestri.tion base"7sCstrin$")
*7sCenumeration value"ab." S)
*7sCenumeration value"01r" S)
*7sCenumeration value"7yz" S)
*S7sCrestri.tion)
*S7sCsim0le-y0e)

The enumeration facet empowers us to choose a single value from amongst numerous
values. In the above case, the type 'vijay' has three enumerated values of abc, pqr and xyz.
In this manner, we can restrict the values that the simpleType can represent.

Let us now add a complexType to our designer. Click on the schema tab on the bottom to
switch to the Schema Designer, and then, drag and drop the complexType onto it, from the
toolbox. The name of the complexType is changed to Mukhi. You can click on the column
next to Mukhi, to view the options that are provided. We prefer to leave it blank. Then, click
on the row below Mukhi. This displays a series of elements, as seen in screen 6.23.

244258241.doc 1!5 od 272
Sceen !.23

Here, we select sequence. Doing so automatically brings up a group box named group1, of
type 'sequence'. The group must contain two felds. So, enter 'f1' in the row below group1,
and then, select 'string' in the column besides it. To add the second feld, click on the next
row and enter the second feld name as 'f2' with the type as 'string'. This brings us to screen
6.24.

Sceen !.24

The frst column has a value of E, which represents an element.

*7sC.om0le7-y0e name"mu5#i")
*7sCse1uen.e)
*7sCse1uen.e)
*7sCelement name"+1" ty0e"7sCstrin$" S)
*7sCelement name"+!" ty0e"7sCstrin$" S)
*S7sCse1uen.e)
*S7sCse1uen.e)
244258241.doc 1!! od 272
*S7sC.om0le7-y0e)

The XML code very clearly specifes a complexType element named Mukhi, which has two
sequences. The second sequence has two felds, named f1 and f2.

The frst sequence is not required. However, we have included it to merely display the visual
efect of the Schema Designer. The above XML is the same code that was revealed to you
some time back.

Now, from the toolbox, select element, and drag and drop it into the form. Change the name
of the element to 'sonal'. For selecting the type, click on the right hand column. This will
show the list of types available, including the type Mukhi. This is shown in screen 6.25.
Select the type Mukhi and witness the changes in the Designer.

Sceen !.25

The screen 6.26 shows us the linkages visually.

244258241.doc 1!7 od 272
Sceen !.2!

Thus, the user-defned types, whether simple or complex, also get added to the list of types.
Now, drag-and-drop one more element from the toolbox in the XML Designer, and name it as
'yyy', as shown in screen 6.27, leaving the type unchanged.

Sceen !.27

Drag the element sonal that was created above, onto this default element. Screen 6.28
shows that the elements get bound to each other, beginning with yyy, followed by sonal and
then, followed by the sequence named Mukhi.

Sceen !.28

Let us now examine the entire XML fle that has been written out by the Schema Designer.

*O7ml version"1.0" en.odin$"ut+R>" O)
244258241.doc 1!8 od 272
*7sCs.#ema id"zzz" tar$et3ames0a.e"#tt0CSStem0uri.or$Szzz.7sd"
element/orm2e+ault"1uali+ied" 7mlns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsCmstns"#tt0CSStem0uri.or$Szzz.7sd"
7mlnsC7s"#tt0CSS444.4(.or$S!001SKMLS.#ema")
*7sCsim0le-y0e name"vijay")
*7sCrestri.tion base"7sCstrin$")
*7sCenumeration value"ab." S)
*7sCenumeration value"01r" S)
*7sCenumeration value"7yz" S)
*S7sCrestri.tion)
*S7sCsim0le-y0e)
*7sC.om0le7-y0e name"mu5#i")
*7sCse1uen.e)
*7sCse1uen.e)
*7sCelement name"+1" ty0e"7sCstrin$" S)
*7sCelement name"+!" ty0e"7sCstrin$" S)
*S7sCse1uen.e)
*S7sCse1uen.e)
*S7sC.om0le7-y0e)
*7sCelement name"yyy")
*7sC.om0le7-y0e)
*7sCse1uen.e)
*7sCelement name"sonal" ty0e"mu5#i")
*S7sCelement)
*S7sCse1uen.e)
*S7sC.om0le7-y0e)
*S7sCelement)
*S7sCs.#ema)

The XSD fle contains a simple type named vijay, followed by a complex type named Mukhi.
Then, there exists an element named yyy that starts with a complexType, followed by a
sequence containing one more element called sonal, of type Mukhi. The tags are duly closed.
Thus, you can see that the creation of schemas has been considerably simplifed by the
Schema Designer. Before proceeding any further, click on File-Save All menu option.

Now, to create a new XML fle, click on File-New-File, and then, in the New File dialog box,
choose XML fle, as before. In the properties window, click on the listbox for the property
targetSchema, as shown in screen 6.29.

244258241.doc 1!" od 272
Sceen !.2"

Select the schema as zzz.xsd or http://tempuri.org/zzz.xsd. The text in the XML fle
changes to the following:

*O7ml version"1.0" en.odin$"ut+R>" O)
*yyy 7mlns"#tt0CSStem0uri.or$Szzz.7sd")
*Syyy)

Since we named the element as yyy having no type, the root element becomes yyy. The
default namespace is determined by the xmlns attribute, which points to the zzz.xsd fle that
we had created.

Then, we click in the XML editor and enter a < sign, as shown in screen 6.30. This displays
the element sonal. Here, we are permitted to enter only sonal, since it is the sole element in
our fle.

Sceen !.3#

This corroborates the fact that the XML fle constantly looks up the XSD fle to ensure that
the data that has been entered, complies with the rules of the Schema fle.

Select sonal, and as before, the ending tag gets created for us. Make sure that the end tag is
placed on a new line. Insert one more blank line within the tags. Now, within the start and
the end tag, enter the < sign. As shown in screen 6.31, the two felds f1 and f2 are depicted,
because the element sonal is of the complexType mukhi, which contains only the two felds
f1 and f2.

244258241.doc 17# od 272
Sceen !.31

Select the feld f1. The end tag immediately shows up. Enter any text such as "vij" in the tag
f1, and then enter the following lines:

*O7ml version"1.0" en.odin$"ut+R>" O)
*yyy 7mlns"#tt0CSStem0uri.or$Szzz.7sd")
*sonall)
*+1)vij*S+1)
*$$$)jo*S$$$)
*Ssonall)
*Syyy)

The end result is exhibited in screen 6.32.

Sceen !.32

244258241.doc 171 od 272
The tag ggg is not a part of the schema. Hence, it is underlined in red. Any tag that does not
meet the schema rules is rejected, and this violation is indicated by a change in the color.
Thus, the editor too points fngers at our mistakes.

By now, you must have realized that Visual Studio.Net makes life much simpler for all of us.
However, it cannot be used to comprehend the Visual Basic language. So, henceforth, upto
the end of this volume, we shall focus purely on programming concepts, without using the
framework.

=. $0ce!tion "andlin1

Henceforth, all the topics would be covered in considerable depth. In one of the previous
chapters, we enlightened you about the errors that occurred only at run time, which the
compiler could not detect. These errors are termed as 'exceptions'. The occurrence of an
exception signifes that something extra-ordinary has transpired, which need not necessarily
be an error.

For instance, in a subroutine, some of the potential errors that may occur are:
The parameter supplied to it could be incorrect.
There could be difculty in opening a fle on disk, etc.

Since a subroutine has no means of returning values to indicate success or failure, it
becomes difcult to identify the cause or the type of error that has occurred.

To be bailed out of a predicament like this, the concept of exceptions comes in handy. For
every distinct type of error that occurs, a unique exception can be thrown.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
end sub
end .lass

>vbc a.vb
>a

$rror
/n.andled $0ce!tion: S+ste).$0ce!tion: "i
at ;;;.Main%&

The Throw statement is the only pathway to execute an exception. This keyword requires an
Exception object. Therefore, the object 'a' is declared as an instance of the Exception class,
where the parameter of "hi" is passed to the constructor. The Throw statement now 'throws'
or 'raises' an exception, and displays the error message as "Hi".

On running the above program, a mammoth dialog box pops up. We request you to click on
the 'No' button, or else you could be transported to the Debugger.

244258241.doc 172 od 272
a.vb
0ubli. .lass zzz
s#ared sub Main()
ab.
System.Console.WriteLine("9+ter ab.")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

$rror
/n.andled $0ce!tion: S+ste).$0ce!tion: .i
at ;;;.abc%&
at ;;;.Main%&

The above example sheds some more light on the concept of Exception Handling. The main
sub has a shared sub named abc, whose sole task is to throw an exception.

The output displayed validates the fact that a part of the code can throw exceptions too.
Since the sub abc throws an exception, the output points to the sub. However, since the sub
abc is called from Main sub, Main also gets displayed.

Thus, whenever we come across multiple lines referring to an exception, we have to read
them in a specifc sequence, i.e. front to back. The closest sub is the one that is responsible
for throwing the exception, and the other subs are the ones that contain the previous subs.

Here, a point to be borne in mind is that the program comes to a grinding halt when an
exception gets thrown. As a consequence of this, none of the code, either in the sub abc or
in the sub main, gets called thereafter, and the application comes to an end.

Under certain situations, this type of abrupt ending of the program is totally unacceptable,
since any sub called from any of the classes could throw an exception and bring the
program to a standstill.

The next program reveals as to how this can be prevented from occurring.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
System.Console.WriteLine(";e+ore ab.")
ab.
System.Console.WriteLine("9+ter ab.")
.at.#
System.Console.WriteLine("6n Cat.#")
end try
System.Console.WriteLine("9+ter try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
244258241.doc 173 od 272
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
Before abc
In Catc.
After tr+

The above program neither displays any exception dialog box, nor does it quit on
encountering the 'throw' statement. It completes execution upto the very end.

The frst WriteLine function executes normally, followed by the call to the sub abc.
Thereafter, the sub throws an exception, as a result of which, all the lines of code after the
'throw' get ignored.

The signifcant point here is that, the sub abc has been placed in a try-catch clause, which
is why the dialog box does not get displayed. Instead, the program executes code in the
'catch', and then, moves out gracefully at the end try statement. No code gets called after
the sub abc has been called.

Thus, by placing all the exception handling code within the catch, all the probable
exceptions can be suitably catered for. The code that is to be placed in the catch block is left
entirely to your discretion.

Depending upon the situation, you may either place all the subs and functions in one
gigantic 'try and catch' statement, or place them in individual 'try and catch' statements.
Visual Basic.Net has no rules in this regard.

a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
System.Console.WriteLine(";e+ore ab.")
ab.
System.Console.WriteLine("9+ter ab.")
.at.# e as System.E7.e0tion 4#en i * ,
System.Console.WriteLine("6n Cat.#")
end try
System.Console.WriteLine("9+ter try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
Before abc

/n.andled $0ce!tion: S+ste).$0ce!tion: .i
at ;;;.abc%&
at ;;;.Main%&
244258241.doc 174 od 272

When we run the above program, the ofending dialog box gets displayed, as before. This
happens because, in addition to the Exception argument, the 'catch' clause also requires a
'when' clause along with a condition. We have created a variable i and set its value to 10.

While catching the exception, the condition is evaluated. Since the condition results in a
value of False, the catch is overlooked, thus leaving it to the system to handle the exception.
It behaves as though the catch statement never existed.

a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
System.Console.WriteLine(";e+ore ab.")
ab.
System.Console.WriteLine("9+ter ab.")
.at.# e as System.E7.e0tion 4#en i * ,
System.Console.WriteLine("6n Cat.# i * ,")
.at.# e as System.E7.e0tion 4#en i ) ,
System.Console.WriteLine("6n Cat.# i ) ,")
System.Console.WriteLine(e.-oStrin$)
end try
System.Console.WriteLine("9+ter try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
Before abc
In Catc. i > '
S+ste).$0ce!tion: .i
at ;;;.abc%&
at ;;;.Main%&
After tr+

The above program does not display any dialog boxes, since it contains two catch
statements:
The frst one handles exceptions when the value of the variable i is less than 5.
The second one caters to the exceptions when the value of i is greater than 5.

Thus, depending on the value of the variable i, one of the two catch statements gets called.

If we change the condition of the frst catch to 'when i > 5', even though both the conditions
are the same, Visual Basic.Net does not complain. This is because, the moment any one of
the conditions gets satisfed, all the other conditions get ignored.

The string representation of the exception object is displayed using the sub ToString, which
is similar to the manner in which error messages are displayed.

244258241.doc 175 od 272
a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
System.Console.WriteLine("/irst try")
try
System.Console.WriteLine(";e+ore ab.")
ab.
System.Console.WriteLine("9+ter ab.")
.at.#
System.Console.WriteLine("6n se.ond Cat.#")
end try
System.Console.WriteLine("9+ter +irst try")
.at.#
System.Console.WriteLine("6n /irst .at.#")
end try
System.Console.WriteLine("9+ter se.ond try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
4irst tr+
Before abc
In second Catc.
After Brst tr+
After second tr+
In the above program, there are two try statements, one ensconced within the other. In the
frst try statement, the WriteLine function gets executes. In the second try statement, the
WriteLine function gets executes once again, without much ado!

The exception thrown by the sub abc is caught in the catch of the inner try statement. Once
the catch completes execution of its code, the program moves from the inner try to the outer
try. Since the exception has already been caught and handled by the inner try, the outer
catch does not catch it again.

Thus, as long as one of the catch statements is able to catch the exception that has been
thrown in the try, the other catch statements will behave as though no exception was
thrown. This would occur even if the condition of the second try statement is satisfed.

Thus, as long as even one catch statement in the sequence catches the exception, none of
the other catch statement gets called.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
ab.
.at.#
System.Console.WriteLine("6n Cat.# ")
+inally
244258241.doc 17! od 272
System.Console.WriteLine("6n /inally")
end try
System.Console.WriteLine("9+ter try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass


ut!ut
In Catc.
In 4inall+
After tr+

The 'fnally' clause is an integral part of the 'try-catch-fnally' statements. The exception that
is thrown can be easily caught in one of the catch statements. However, when there are
multiple catch statements, only one of them will get executed.

One problem that could befall us is that, there could be some common code that needs to be
executed for all the catch statements. One solution is to repeat the same code in each 'catch'
statement. The other option would be to use the 'fnally' clause. After all the statements in
the 'catch' block have been executed, just before the 'try' clause ends, the code placed in the
'fnally' block gets called.

Now, comment out the line of code that calls the sub abc, thereby, evading all exceptions
that get thrown. Thus, when the program is executed, no exceptions are thrown.
Nevertheless, the code written in the 'fnally' clause gets called.

a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
System.Console.WriteLine("/irst try")
try
System.Console.WriteLine(";e+ore ab.")
ab.
System.Console.WriteLine("9+ter ab.")
.at.# 4#en i ) 100
System.Console.WriteLine("6n se.ond Cat.#")
+inally
System.Console.WriteLine("6n se.ond +inally")
end try
System.Console.WriteLine("9+ter +irst try")
.at.#
System.Console.WriteLine("6n /irst .at.#")
+inally
System.Console.WriteLine("6n +irst +inally")
end try
System.Console.WriteLine("9+ter se.ond try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
244258241.doc 177 od 272
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
4irst tr+
Before abc
In second Bnall+
In 4irst catc.
In Brst Bnall+
After second tr+

This program initiates two new concepts. As before, there are two 'try' statements. The sub
abc throws an exception, which the catch is unable to catch since the variable i has a value
less than 100, thereby causing the condition to evaluate to false. Now, the onus falls on the
outer try to catch the exception.

However, before exiting the inner try, it frst calls the 'fnally' clause of the inner 'try-catch-
fnally' block, and then, it executes code in the outer 'catch' statement. Thereafter, it
executes the 'fnally' block of the outer 'catch' statement. In case, the outer 'catch' fails to
catch the exception, the system will display the appalling dialog box, which has been shown
earlier.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
ab.
.at.#
System.Console.WriteLine("6n Cat.# E7.e0tion")
end try
end sub
s#ared sub 01r
dim a as System.E7.e0tion
a ne4 System.E7.e0tion()
-#ro4 a
end sub
s#ared sub ab.
01r
end sub
end .lass

ut!ut
In Catc. $0ce!tion

This example is a variation of the above example. It proves that when the exception has to
be caught, it moves up the sub hierarchy. Thus, the concept is that someone somewhere
should be able to catch the exception.

The Main subroutine calls abc, which in turn calls pqr. The sub pqr throws the exception.
Since there is no catch block in pqr, the catch within the sub abc should normally get
called. However, there is no catch present in the abc block, due to which, the catch in the
main function is evoked. The catch in the Main block displays 'In Catch Exception'.

244258241.doc 178 od 272
However, if the sub Main too does not provide for the catch clause, the exception based
dialog box will get displayed. Thus, the presence of at least one try catch in the Main
subroutine is strongly prescribed.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
ab.
.at.#
System.Console.WriteLine("6n Cat.# ")
e7it try
System.Console.WriteLine("6n Cat.# 1")
+inally
System.Console.WriteLine("6n /inally")
end try
System.Console.WriteLine("9+ter try")
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion("#i")
-#ro4 a
System.Console.WriteLine("9+ter t#ro4")
end sub
end .lass

ut!ut
In Catc.
In 4inall+
After tr+

The program introduces the statement of 'Exit Try', which ceases to process all the 'catch'
statements, and exits from the 'try' gracefully. Thus, the second occurrence of the WriteLine
function does not get executed.

The job of Exit Try is to abandon the try statement instantly. However, the program is not
permitted to sneak out of the try statement, without frst paying homage to the fnally
clause. The output reveals that the code in the fnally clause has been executed before the
'try' ended.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
ab.
.at.# e as System.E7.e0tion
System.Console.WriteLine("6n Cat.# ")
end try
end sub
s#ared sub ab.
dim a as 777
a ne4 777()
-#ro4 a
end sub
end .lass
.lass 777
6n#erits System.E7.e0tion
end .lass
244258241.doc 17" od 272

ut!ut
In Catc.

An exception is simply any class that is derived from the exception class. The class xxx is an
exception handling class, since it derives from the class exception. In the sub abc, an
exception of type xxx is thrown. Note that it is not of type Exception.

However in the catch, the exception that is caught is of type Exception, and not of type xxx.
This is absolutely permissible, since all exceptions get caught by the type Exception, since
they derive from it.

a.vb
0ubli. .lass zzz
s#ared sub Main()
try
ab.
.at.# e as 777
System.Console.WriteLine("6n Cat.# 777")
.at.# e as System.E7.e0tion
System.Console.WriteLine("6n Cat.# E7.e0tion")
end try
end sub
s#ared sub ab.
dim a as 777
a ne4 777()
-#ro4 a
end sub
end .lass
.lass 777
6n#erits System.E7.e0tion
end .lass

ut!ut
In Catc. 000

The appropriate approach to catch exceptions would be to check the exceptions that are
thrown by a sub. The above program has only one sub abc, which throws only one exception
of type xxx. However, if ten diferent types of exceptions are thrown, then good programming
practice dictates that each of the ten exceptions should be caught using diferent catch
statements.

Every catch should handle its exception individually. The exception that is not handled
separately can be caught by the type Exception. Now, merely reverse the exceptions of the
earlier program.

.at.# e as System.E7.e0tion
System.Console.WriteLine("6n Cat.# E7.e0tion")
.at.# e as 777
System.Console.WriteLine("6n Cat.# 777")

ut!ut
In Catc. $0ce!tion

This creates a quandary, since the second exception of type xxx shall never get caught. This
is because, the frst exception is of type Exception, which will catch all the exceptions.
244258241.doc 18# od 272

a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
ab.
.at.# 4#en i * ,
System.Console.WriteLine("6n Cat.# E7.e0tion i * ,")
.at.# e as 777
System.Console.WriteLine("6n Cat.# E7.e0tion 777")
.at.# e as System.E7.e0tion 4#en i ) 100
System.Console.WriteLine("6n Cat.# E7.e0tion i ) 100")
.at.# e as System.E7.e0tion 4#en i 10
System.Console.WriteLine("6n Cat.# E7.e0tion i 10")
.at.#
System.Console.WriteLine("6n Cat.# E7.e0tion")
end try
end sub
s#ared sub ab.
dim a as System.E7.e0tion
a ne4 System.E7.e0tion()
-#ro4 a
end sub
end .lass
.lass 777
6n#erits System.E7.e0tion
end .lass

ut!ut
In Catc. $0ce!tion i I #0

The above example amply substantiates the fact that, a program can contain multiple catch
statements, which can have a combination of both, the 'exception' and the 'when' clause.
However, for the exception to be caught, both these conditions must be satisfed.

The frst catch ascertains whether the value contained in variable i is less than or equal to
5. Since i has been initialized to 10, the condition fails, thereby ignoring the catch for the
exception. The second catch catches all exceptions of type xxx. The condition of this catch
statement also does not get satisfed, since the exception thrown is of type Exception.

The third catch contains both, an Exception type, as well as a 'when' clause. The Exception
to be caught is of type Exception, which evaluates to true. However, the when clause
evaluates to false since i is not greater than 100. As a result, the catch does not get called.


The last catch clause meets both the conditions. Therefore, the fnal outcome is a value of
True. Thus, we can build as many conditions as we like in a 'catch' statement. However, for
an exception to be caught, all the conditions must be met.

The rationale behind the concept of exception handling is that, it enables us to catch errors
that occur during program execution while allowing the program to continue running. Thus,
every program must have at least one try and catch encompassing the entire code, or else,
the user may encounter the irksome dialog box, which could scare the wits out of him!

244258241.doc 181 od 272
Keep in mind that even code written by Microsoft or other software companies could
generate exceptions, which need to be caught.

Exceptions are deemed to be very useful in the context of constructors, since constructors
are incapable of returning a value. Constructors contain considerable amount of code, and if
any of the code fails, there is no mechanism by which the constructor can notify such
failure. The best resolution of such a situation is to throw an exception.

Another convenience of exceptions is when multiple fles are opened concurrently in an
application. Each fle requires almost identical error checks to be performed on it. No
programmer of sound mind would want to write the same error check multiple times.
Hence, he is bound to take the easy way out by refraining from including error checks
altogether. This could result in fatal errors.

To avoid such a situation, a try-catch statement can be incorporated, which will ensure that
all error handling code is placed in a single location. This simplifes the procedure of error
checks while using multiple fles, and it obviates the need to use the same code repetitively.

Visual Basic supports two types of exceptions:
Structured - which have been explicated earlier.
Unstructured - which are so named due to their heritage.


The statement 'On Error' has been implemented. However, we will not be explaining this
concept in this book.

The one thing to be borne in mind is that structured and unstructured exceptions cannot be
used simultaeously in the program.

a.vb
0ubli. .lass zzz
dim s#ared i as inte$er 10
s#ared sub Main()
try
ab.
.at.# e as System.E7.e0tion
System.Console.WriteLine(e.Hel0Lin5 V "." " e.Messa$e V "." " e.Sour.e V "." " e.Sta.5-ra.e
V "." V e.-ar$etSite.-oStrin$)
end try
end sub
s#ared sub ab.
dim a as 777
a ne4 777("vijay")
-#ro4 a
end sub
end .lass
.lass 777
6n#erits System.E7.e0tion
0ubli. sub ne4(i as strin$)
mybase.ne4(i)
end sub
end .lass

ut!ut
.vi*a+.a. at ;;;.abc%&
244258241.doc 182 od 272
at ;;;.Main%&.5oid abc%&

In the above example, we have endeavoured to print out most of the properties of the
Exception class.

The frst property of HelpLink displays a null value. This property is used to locate the help
fle that provides greater details about the Exception that is thrown.

The next member is Message, which furnishes some more information about the Exception
that was thrown. The message displayed is normally the string that is passed to the
constructor. We have passed a value of 'vijay' to the xxx constructor. The class xxx is derived
from the Exception class. The frst line in the constructor of this class calls the base class
and assigns it the string that has been passed to it. Due to this, the text 'vijay' gets
displayed.

If you place the base class call within comments, the Message property will display
'Exception of type xxx was thrown'. This is the default string assigned to the Message
property.

The a.exe application is executed. It has been created from the Visual Basic.Net source fle
named a.vb. Due to this, the Source property has been assigned the value of 'a'. When the
Visual Basic.Net compiler is executed using the command vbc /out:b.exe a.vb, the name of
the exe fle changes to b.exe, thereby resulting in the Source property now displaying 'b'.

The StackTrace property is responsible for listing the subs that are responsible for throwing
the exception. As mentioned earlier, this list has to be read in a specifc sequence. The frst
line contains the sub that has thrown the exception. The subsequent subs are the ones that
contain the preceding subroutine.

The TargetSite property is of type MethodBase, which represents a method that throws the
exception. The ToString function displays the signature of the function.

A sub does not return a value, and hence, is not a function. The word Void denotes no
return type. A function which has a return type of void, actually does not return any value
at all. This makes the sub a function with a void return type. Subs are included in Visual
Basic.Net because they were an integral part of the old VB language.
>. Basics

Before exploring the depths of the Visual Basic language, let us frst focus on some core
issues. The frst version of Visual Basic was 1.0. We have intentionally mentioned this fact
here, because the software giant Microsoft is not always known to begin all its product
versions with the Version Number 1.0.

Visual Basic was not initially conceived as a language. It was designed mainly as a product
that used the language. Actually, the language was developed as an afterthought, since
Microsoft's main focus was on building the Visual Basic product. Ever since its inception,
Visual Basic has donned the mantle of the most popular language amongst Windows
programmers.

244258241.doc 183 od 272
At that stage, the only other competitors in the market were Power Builder and Delphi.
Incidentally, the designer of the above two products has also designed the .Net programming
language named C#. When Microsoft released COM, i.e. the Component Object Model, it
used Visual Basic 4.0 to showcase its efcacy. However, in the current scenario, Visual
Basic has been replaced by Visual Studio.Net. According to the big boys at Microsoft, Visual
Basic is considered to be the easiest entry-point into the Microsoft.Net platform. We are not
going to argue on issue, since we could but not agree with them anymore!
The designers of Visual Basic did not merely extract random ideas out of their hats to
develop this product. They sat down and designed it with a specifc target audience in mind.
The fact that the largest number of programmers the world over are Visual Basic
programmers is indeed a tribute to their genius.

To retain the loyalty of this large posse of Visual Basic programmers, Microsoft has very little
choice but to design Visual Basic.Net in such a manner that a Visual Basic programmer
would feel as comfortable using it as a fsh in water. If they had not done so, there was
imminent danger of the trillions of Visual Basic programmers jumping ship to some other
language ;). Visual Basic.Net is thus a descendant of Visual Basic.

The syntax and the semantics of the language are easy to understand and the counter-
intuitive features have been circumvented. The language is also designed to be an integral
part of the .Net framework.

All .Net languages compile to IL or Intermediate Language. We are aware of this conversion
since we have written a book on IL. This concept has been introduced to ensure that the
classes created in one language can be used in another language with ease. As a result of
this, there is no way of ascertaining whether the Console class has been written in C# or in
Visual Basic.Net or in some other .Net language.

In order to implement this concept, and to make it ft into the overall framework of the .Net
world, the features of Visual Basic.Net are quite divergent from those of the older Visual
Basic. Thus, Visual Basic.Net is considered to be a reasonable upgrade of Visual Basic. This
fact is also ratifed by what is stated in the documentation.

The original designers of Visual Basic had intended it to be a quick and easy language that
people could use, without having any formal training. The emphasis of Visual Basic always
was to facilitate users to build applications with ease. It has succeeded remarkably in its
original intention, a fact that is vindicated from the exceptional success of the product.

However, the language disconcerts the purists, since it infringes the cardinal rules of the
programming world. But hey, who cares? Why fx a thing that already works well?

In Visual Basic.Net, the Enter key signals the end of a line. Most languages such as C, C++,
C# and Java use the semi-colon to signal the end of a statement. The ABAP/4 programming
language from SAP uses the dot, like we do in the English language. However, the designers
of Visual Basic.Net mutually decided to use the Enter key for this purpose.

a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine("-#is line is" &
"bro5en over t4o line")
end sub
end .lass
244258241.doc 184 od 272

$rror
c:\il\a.vb%3& : error BC3020#: $0!ression e0!ected.

The above program is bound to generate an error, since we are not permitted to press Enter
midway through a line. We unwittingly pressed Enter, since the line was becoming too
protracted. However, this is unacceptable. There is a very simple remedy to this malady,
which is, to use the _ underscore character.

System.Console.WriteLine("-#is line is" & F
"bro5en over t4o line")

Thus, whenever the Visual Basic.Net compiler bumps into the underscore character, it is
aware that the string is incomplete, and continues its search to the next line. Furthermore,
we cannot break up a string enclosed within double quotes. Even an underscore character
would not be able to help in such cases.

The program given below is distinct from those we have encountered so far. It substantiates
the fact that, if and when the reserved words like string and class are used in any other
context, they need to be placed within square brackets.
a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine(T.lassU.Tstrin$U)
end sub
end .lass
.lass T.lassU
0ubli. s#ared Tstrin$U as inte$er 10
end .lass

ut!ut
#0

The program has two classes, zzz and class. String is a shared variable of type integer in the
class. Now, to access the variable in the main subroutine, the syntax to be used is
'class.variable'. Hence, the WriteLine function has a string variable, which is accessed by
using [class].[string].

Mark the use of square brackets. The use of square brackets with the identifer, is also
known as 'escaping' the identifers.

We would advise you to refrain from using keywords as identifers, although they are legally
valid, as depicted above. There are only about a hundred such keywords in Visual Basic.Net.
The keywords conform to the Unicode 3.0 Standard Report 15 Annex 5.

Languages such as Chinese and Japanese are extremely visual, and hence, the ASCII
character set, which is used for representing the English language, becomes too restrictive
in their case. The Unicode standard is an approach, by means of which, characters from all
languages of the world can be represented. Unicode, which is an international standard,
uses 16 bits, instead of the regular 8 bits used by the ASCII set.

Another rule for an identifer to adhere to is that, if it begins with an underscore character,
it must have at least one more character following it.

244258241.doc 185 od 272

The identifers have a constraint in the form of their length, i.e. their maximum size can only
be 1633 characters. This infuriates us, since only a programmer bereft of all reason, would
create a variable exceeding 100 characters in lengths. Yet, the documentation says that the
identifer length is restricted to the above. Perhaps, in the next version, the limit may be
eked out to 32000 characters! Note that the identifers in Visual Basic.Net are case-
insensitive.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as strin$
aW "#i"
System.Console.WriteLine(aW)
end sub
end .lass

ut!ut
.i

An identifer or a variable name may be followed by some special characters, such as $ or @.
These special characters are called 'type characters' and they work with non-escaped
identifers. The variable name mentioned above remains as 'a'. However, the $ sign ensuing
it, indicates that the variable type is a string.

Therefore, the variable is declared in the normal way. The use of 'type' character is optional.
It serves the purpose of visually revealing the data type of the variable.

aX "#i"

$rror
c:\il\a.vb%4& : error BC302==: 7+!e c.aracter 'J' does not )atc. declared data
t+!e 'Strin1'.

Change the $ sign to @. Its outcome is an error, because the $ denotes a string, whereas,
the @ denotes a number or a long. Thus, in spite of the type character being optional, we are
not authorized to use it in inappropriate contexts.
We cannot lodge spaces or white space characters between the variable and the type
identifer. Also, the type characters cannot be placed on entities that do not have a type,
such as a namespace or a classname. Therefore, the example given below, leads to an error,
since the type identifer $ has been positioned in front of the class name.

0ubli. .lass zzzW

$rror
c:\il\a.vb%#& : error BC304?>: 7+!e declaration c.aracters are not valid in t.is
conte0t.

The keyword mentioned above signifes something special, and has certain rules associated
with it, which need to be followed meticulously. In order to learn any language, we have to
master the use its keywords.

A 'literal' is a constant or a textual representation of some value. We have six diferent types
of literals. The 'boolean literal' can take one of the two values, True or False.
244258241.doc 18! od 272

a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine(&H+)
System.Console.WriteLine(&o1!)
end sub
end .lass

ut!ut
#'
#0

The integer literal can represent numbers in three diferent bases. By default, we humans
are habituated into using numbers that are in the decimal notation or numbers with the
base 10.

The above example displays numbers in hex. Hence, the number starts with &h. A hex
number is represented, not merely by the digits from 0 to 9, but also by the characters from
A to F. Thus, the digit A stands for 10 and F stands for 15. In the decimal numbering
system, each digit is multiplied with an order of 10, while in hex, it is multiplied by an order
of 16.

A number beginning with &o represents an octal number that uses the base of 8. Thus, all
numbers in octal consist of digits from 0 to 7 only. Every individual digit is multiplied by a
order of 8.

While working with computers at the bit level, it is relatively easier to work with the hex and
octal numbering systems, rather than with the decimal system. However, you could spend a
lifetime in the computer world, and yet, never chance upon a number in octal or hex!

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim i as inte$er
i 10000000000000
System.Console.WriteLine(i)
end sub
end .lass

$rror
c:\il\a.vb%4& : error BC3043@: Constant e0!ression not re!resentable in t+!e
'Inte1er'.

You and I may snooze of at the wheel, but the Visual Basic.Net complier does not sufer
from any such malady. It is hawk-eyed. The literal integer has a specifc range of values, and
if we exceed it, the above error would get generated.

a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine("Hi ""<ijay""")
end sub
end .lass

244258241.doc 187 od 272
ut!ut
"i 25i*a+2

A string 'literal' consists of anything enclosed within double inverted commas, as we had
explained earlier. However, when a double inverted comma is to be inserted in the string, an
additional set of double inverted commas is required to be positioned back to back. The
following characters are used as separators: ( | ) | ! | # | , | . | :.

When the Visual Basic.Net compiler is executed, it frst scans the code. This process is
known as 'lexical analysis'. Then, it has an option of including specifc code of ours, in the
output fles generated. This process is known as 'conditional compilation'. It is demonstrated
in the next example.

a.vb
G.onst z true
0ubli. .lass zzz
s#ared sub Main()
ab.
end sub
s#ared sub ab.
Gi+ z t#en
System.Console.WriteLine("z true")
Gelse
System.Console.WriteLine("z +alse")
Gend i+
end sub
end .lass

ut!ut
; true

The preprocessor is a program that normally is part of the Visual Basic.Net compiler. It
scrutinizes the code at a very early stage in the whole process. It only looks at lines
beginning with a # symbol, also known as a preprocessor directive.


The preprocessor directive, along with the word 'const', is part of the syntax, which is set to
a value of True. Any value, including numbers, can be assigned here, as long as it is not a
string, since string values cannot be converted into boolean values.

The sub called abc has an 'if' statement, which begins with a # sign, followed by the 'if'
statement. This is the preprocessor equivalent of the 'if' statement. The syntax remains the
same. This directive checks for the value in the 'const'.

The value of z is checked to determine if it is true or false. If it is true, then all the code
between the 'if' and 'else' gets included in the resultant code. But, if the value evaluates to
false, the code between the 'else' and 'end if' gets included. In the above case, the Visual
Basic.Net compiler ignores the 'else' block, thereby totally sidelining the second WriteLine
function.

a.vb
G.onst z true
0ubli. .lass zzz
s#ared sub Main()
ab.
244258241.doc 188 od 272
end sub
s#ared sub ab.
Gi+ z t#en
dim i as inte$er
Gelse
dim j as inte$er
Gend i+
System.Console.WriteLine(i"j)
end sub
end .lass

ut!ut
c:\il\a.vb%#2& : error BC304'#: (a)e '*' is not declared.

The above example lucidly explains the concept described above. The directive of 'if-else-end
if' is used to create either of the variables i or j, depending upon the value stored in the
const z. Since z holds the value of true, only the variable i is created.
The DIM statement for j gets knocked out of the code, since the 'else' block is snubbed
completely. When the Visual Basic.Net compiler kicks in, the only variable visible to it is i,
and not j. Resultantly, it hurls the error message at us, stating that j has not been declared.

Rewrite the above const statement as :

G.onst z not#in$

The error message now reads as :

c:\il\a.vb%#2& : error BC304'#: (a)e 'i' is not declared.

When the const variable is initialized to nothing, a default value of false is assigned to the
variable. Also, the const variable assumes a default value of false, when the variable has not
been created in the program. If a variable is created, it must be assigned some value, or else,
the following error will be thrown:

c:\il\a.vb%#& : error BC3024@: 'I' e0!ected.

There are two ways of creating a preprocessor variable; one is by using the const directive,
and the other is by employing an option of the command line compiler. Eliminate the line in
the above program that creates a const variable z, and then, run the Visual Basic.Net
compiler using the command:

vbc Cd:;Itrue a.vb

c:\il\a.vb%##& : error BC304'#: (a)e '*' is not declared.

The /d option with the Visual Basic.Net compiler creates a preprocessor constant. Thus, a
constant z is created, with its value set to true. The variable j is not defned anywhere, since
the 'else' block has been ignored. Hence, the above error message gets displayed. Had we set
the value of the variable z to false, an error message would have been generated, informing
us that the variable i has not been created.

This method demonstrates the most common use of preprocessor variables. Under normal
circumstances, the program code has a large number of debugging statements sprinkled all
over the program. The example given below delineates this.
244258241.doc 18" od 272

a.vb
0ubli. .lass zzz
s#ared sub Main()
ab.
end sub
s#ared sub ab.
Gi+ 2E;NJ t#en
System.Console.WriteLine("2ebu$")
Gend i+
end sub
end .lass

There are many things that may go awry while developing programs. Therefore, at every
stage, checks need to be implemented. For this very reason, the code is infused with plenty
of statements, which reveal the activities to the program, while it is running.

The WriteLine function may also be used for this purpose. However, the only failing of this
approach is that, millions of WriteLine functions will have to be deleted, after they have
served their utility.

So, the best solution is to place all the debugging code in a '#if' statement using the variable
DEBUG. At compile time, the DEBUG variable is set to True. On seeing the value of true, all
the WriteLine statements will get executed, thus providing a trace of the events. If the
debugging facility needs to be switched of, i.e. when the program is to be switched to the
Release mode, the DEBUG variable can be deleted or set to False. This would result in all
the WriteLine functions being ignored in the program.

This is just one example of the myriad uses of the preprocessor variables that can be
created at the command line.
@. Classes9 Interfaces and Structures

The most remarkable of all the entities encountered so far is the class, since it creates types
that encompass all the variables/objects and methods within it. Let us devote some time
discerning the various entities that can be placed inside a class.

a.vb
0ubli. .lass zzz
6n#erits 777%yyy
s#ared sub Main()
ab.
end sub
s#ared sub ab.
end sub
end .lass
0ubli. .lass 777
end .lass
0ubli. .lass yyy
end .lass

$rror
c:\il\a.vb%2& : error BC30#2#: 'In.erits' can a!!ear onl+ once wit.in a 'Class'
state)ent and can onl+ s!ecif+ one class.

244258241.doc 1"# od 272
There are no means by which a class may be derived from two classes simultaneously. This
is not permissible even in the .Net world. Owing to this reason, the above error is shown,
since the class zzz has been derived from two classes viz. xxx and yyy concurrently.

However, the resolution to this quandary would be to derive the class xxx from the class yyy,
and then, derive the class zzz from the class xxx. Thus, it is evident that Visual Basic.Net
and the entire .Net world espouses 'single inheritance' and not 'multiple inheritance'.

In certain situations, when the Visual Basic.Net compiler encounters an error, it loses its
poise and composure, and begins to spew out error messages that are really not errors.
Thus, only the frst or second error messages are generally signifcant; the rest of them can
be safely ignored.

It is imperative to mention the type name after the 'inherits' statement. The 'inherits'
keyword is not a part of the class statement. It is a statement in its own right. Thus, it must
be positioned in the frst line after the class statement. The only entity that can follow the
inherits statement is the ordinary comment.

Interfaces

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
end .lass
0ubli. inter+a.e 777
end inter+a.e

The above example does not lead to any errors at compile time, in spite of the introduction of
the new word i.e. 'interface'. Further, the class yyy does not use 'inherits' statement;
instead, it employs the 'implements' statement. After the 'implements' statement, comes the
name of an interface, viz. xxx.
An interface is created in the same manner as a class. If you replace the word 'implements'
with 'inherits' after the defnition of the class yyy, it will lead to the following error:

$rror
c:\il\a.vb%?& : error BC302'>: Classes can in.erit onl+ fro) ot.er classes.

Thus, Visual Basic.Net maintains an unambiguous distinction between an interface and a
class.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e
244258241.doc 1"1 od 272

$rror
c:\il\a.vb%?& : error BC30#4@: '+++' )ust i)!le)ent 'Sub abc%&' for interface '000'.

The above example clearly highlights the disparity between an interface and a class. The
interface xxx has a sub abc without the end sub. Also, no code is mentioned after the sub.
This too does not result in any error. However, when the class yyy implements the interface
xxx, all the subs defned in the interface xxx have to be created in the class yyy.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
0ubli. sub ab. im0lements 777.ab.
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e

The above error evaporates since the sub abc has been created with the end sub, in the
class yyy. We have consciously precluded any code in the sub abc. However, this does not
generate any error. Thus, the compiler mainly enforces the condition that, every sub that is
created should contain the end sub. It is not concerned about whether the sub contains any
code or not.

A point to be noted here is that following the keyword 'implements', the name of the
interface is specifed, along with the sub whose code is being written. Since we are writing
code for the sub abc, which is present in the interface xxx, the word 'implements' is followed
by the sub xxx.abc. If we uproot 'implements xxx.abc' from sub, we will be confronted by the
error shown below:

$rror
c:\il\a.vb%?& : error BC30#4@: '+++' )ust i)!le)ent 'Sub abc%&' for interface '000'.

Using 'implements' with the sub, eases the compiler's job, since it then becomes aware of
which function is being defned in the class. Thus, if an interface has 15 subs/functions, it
is mandatory for all 15 of them to contain code. If the code for even one of them is omitted,
an error will get generated.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777%iii
0ubli. sub ab. im0lements 777.ab.
end sub
0ubli. sub ab. (i as inte$er )im0lements iii.ab.
end sub
end .lass
0ubli. inter+a.e 777
244258241.doc 1"2 od 272
sub ab.
end inter+a.e
0ubli. inter+a.e iii
sub ab.(i as inte$er)
end inter+a.e

The above example has two interfaces xxx and iii, both having a sub defnition of abc, but
with diferent signatures. The sub abc takes one parameter in interface iii. Further, the
class yyy now implements two interfaces. Thus, a class can implement from multiple
interfaces, but can inherit only from one class.

While defning the subs, the 'implements' keyword identifes the sub that is being defned.
This is obligatory, since a class can implement multiple interfaces.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim z as zzz
z ne4 zzz()
z.ab.
end sub
sub ab.
dim a as yyy ne4 yyy
dim b as 777 ne4 yyy
dim . as iii ne4 yyy
a.ab.
a.ab.(10)
b.ab.
..ab.(100)
end sub
end .lass
0ubli. .lass yyy
6m0lements 777%iii
0ubli. sub ab. im0lements 777.ab.
System.Console.Writeline("ab. 777")
end sub
0ubli. sub ab. (i as inte$er )im0lements iii.ab.
System.Console.Writeline("ab. iii &0'" % i)
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e
0ubli. inter+a.e iii
sub ab.(i as inte$er)
end inter+a.e

ut!ut
abc 000
abc iii #0
abc 000
abc iii #00

In the example above that is sizeable by any standard, frst an instance z of zzz is created,
and then, the sub abc is called of it. In the abc function, three objects, each of a diferent
data type, are created as instances of yyy. The yyy class implements the two interfaces
named xxx and iii. Therefore, an iii object can be equated with an xxx object.
244258241.doc 1"3 od 272

There are two crucial points that have been purveyed in this program:
Firstly, an interface is akin to a class, which can be used as a data type.
Secondly, we can equate base types not only with derived types, but also with
interface types, to classes that implement those types.

However, there is a small caveat here. Rewrite the dim statement that creates an instance of
object b as follows:

dim b as 777 ne4 777


This results in the following error message:

$rror
c:\il\a.vb%@& : error BC303=': '(ew' cannot be used on an interface.

This is one of the few error messages, which is English-like and easy to understand.

An interface is not permitted to have an instance variable, because an instance of an
interface would never be created. Addition of an instance variable will result in the compiler
generating the following error:

$rror
c:\il\a.vb%#0& : error BC30?02: Interface )e)bers )ust be )et.ods9 !ro!erties9
events9 or t+!e deBnitions.

Thus, to conclude this discussion, we reiterate that an object can be instantiated of a class,
but not of an interface. However, an interface type can be equated with a class, provided that
the class implements the interface.

Since the object 'a' is of type yyy, the two subs named abc, which are present in the
interfaces of xxx and iii, can be called. The object 'b' is of type xxx; hence, we are only
allowed to call the sub abc from the xxx interface, i.e. the one without any parameters. If we
rewrite the line as b.abc(1000), we get the following error:

$rror
c:\il\a.vb%#3& : error BC300'=: 7oo )an+ ar1u)ents to '8ublic Sub abc%&'.

The error is obviously expected, since the interface xxx does not have a sub abc that expects
one parameter. The object 'c' of type iii can however make this call, since it has a sub abc
that accepts one parameter.

Now, bring in a small change, i.e. replace the sub abc, which accepts one parameter in the
interface iii, with one that expects no parameters. This will result in making the signatures
of both the abc subs identical. Obviously, the parameter i in the WriteLine function, needs to
be eradicated before making the call. This results in the following error blowing up in the
face:

$rror
c:\il\a.vb%#?& : error BC302?@: Met.od 'abc' .as )ulti!le deBnitions wit. identical
si1natures.

244258241.doc 1"4 od 272
This exercise corroborates the point that, in spite of having identical signatures, the objects
b and c can easily identify the call to their abc routine. Nevertheless, it becomes easy for the
compiler to identify which abc is to be called, since they are interface types. However, in case
of object 'a' of type class yyy, the bewilderment persists, since it cannot fgure out which
subroutine is to be called, the sub xxx or the sub iii.

a.vb
!ublic class ;;;
s.ared sub Main%&
end sub
end class
!ublic class +++
I)!le)ents 000
!ublic sub abc i)!le)ents 000.abc
end sub
end class
!ublic interface 000
sub abc
end sub
end interface

$rror
c:\il\a.vb%#2& : error BC3042@: '$nd Sub' )ust be !receded b+ a )atc.in1 'Sub'.

While running the above program, we almost believed that we were aficted with the illness
of the eye, because we stumbled upon an error, despite having clearly specifed an 'end' sub
statement with every single sub statement. The error is comes about because an interface
cannot have an 'end' sub, since it is not authorized to contain any code. Thus, the inclusion
of an 'end' sub in the 'interface' causes confusion and generates incorrect error messages.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
in#erits 000
6m0lements 777
end .lass
0ubli. inter+a.e 777
end inter+a.e
0ubli. .lass 000
end .lass

A class can contain both the statements simultaneously, i.e. of 'inherits' and of
'implements'. The only restriction here is that inheritance is permitted from only a single
class, whereas, no such restriction is applicable to interfaces.

In certain situations, the Visual Basic.Net compiler is a stickler with regard to the sequence
of the statements. Thus, if we interchange the sequence of 'inherits' and 'implements' as
follows:

.lass yyy
im0lements 777
in#erits 000

244258241.doc 1"5 od 272
the following error gets generated:

$rror
c:\il\a.vb%=& : error BC30?>3: 'In.erits' state)ent )ust !recede all declarations in a
class.

Just as certain incidents in life are inexplicable, there exist some rules in programming
languages, which are truly enigmatic. There is no sound reason for insisting on the above
sequence, but who pays any heed to our opinion anyway?! This is the reason why people get
emotional while using idiosyncratic languages.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. inter+a.e bbb
sub ab.
in#erits ...
end inter+a.e

$rror
c:\il\a.vb%=& : error BC303'=: 'In.erits' state)ents )ust !recede all declarations in
an interface.

A sub contained in an interface, must have the 'inherits' statement posited at the very start
of the sequence, as in the case of a class. Infringement of this rule is a graver ofence than
the fact that the interface ccc does not exist. Maintain the sequence and we assure you that
you will not come to grief.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
0ubli. sub ab. im0lements 777.ab.
end sub
end .lass
0ubli. inter+a.e 777
0ubli. sub ab.
end inter+a.e

$rror
c:\il\a.vb%##& : error BC302=0: '8ublic' is not valid on an interface )et.od
declaration.
Modifers such as 'public' cannot be used with interfaces. Thus, in an interface that uses a
sub or a function or a property, only the two modifers of Overloads or Default are
permissible. Modifers like Public, Private, Friend, Protected, Shared, Static, Overrides,
MustOverride or Overridable are strictly forbidden.

We have not expounded the modifers Static or Default as yet. But, at times, we may be
compelled to use words that we have not explained, for the sake of completeness and
comprehensiveness of the code.

244258241.doc 1"! od 272
An interface may contain properties, methods and events, which must be implemented by a
class that derives from it. The ability to create interfaces, is one of the most innovative
features of Visual Basic.Net as compared to the older VB. The older VB was infested with a
shortcoming was that, interfaces could be 'used' or 'consumed', but not created. This also
fnds a mention in the documentation.

An interface is a distinct entity from a class, which does not perform any worthwhile role by
itself. It comes into play only when a class decides to implement it. Historically, an interface
represents a contract, wherein a class has to implement all the subs, properties and events
within an interface. If this condition is not met, an error is generated. A class cannot
implement an interface partially. Also, no aspect of an interface can be modifed during its
implementation.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
0ubli. +un.tion ab. as strin$ im0lements 777.ab.
end +un.tion
end .lass
0ubli. inter+a.e 777
+un.tion ab. as inte$er
end inter+a.e

$rror
c:\il\a.vb%?& : error BC30#4@: '+++' )ust i)!le)ent '4unction abc%& As Inte1er' for
interface '000'.

In the above example, the function abc returns an integer in the interface xxx, whereas, the
function returns a string in the class yyy. Since we have deviated from the precise defnition
of the class, an error is generated.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
0ubli. +un.tion ab. as strin$ im0lements 777.ab.
end +un.tion
0ubli. +un.tion ab. as strin$
end +un.tion
end .lass
0ubli. inter+a.e 777
+un.tion ab. as strin$
end inter+a.e

$rror
c:\il\a.vb%?& : error BC30#4@: '+++' )ust i)!le)ent '4unction abc%& As Strin1' for
interface '000'.
c:\il\a.vb%=& : error BC302?@: Met.od 'abc' .as )ulti!le deBnitions wit. identical
si1natures.

244258241.doc 1"7 od 272
It is the examples like these, which make this book stand out from the ordinary! The
program has an interface, with a function bearing the same defnition or signature, as an
independent function in the class. The sub abc from the interface xxx and an independent
sub abc, are both defned to return a string.

The error was anticipated for reasons that have been stated earlier. However, the error
message that is emitted is very diferent from what we had expected. The compiler frst
examines the independent sub abc. It searches for the keyword 'implements' after the sub
name. When it is unable to locate it, the compiler fags an error.

The compiler then encounters the sub abc containing the 'implements' clause. It confesses
its imprudence, since it did not perform this check earlier, and then, it generates an error.
Just as it is almost impossible to fathom how a woman's mind works, it is equally
impossible to fgure out how the compiler decides on the error message to be displayed.

We once again reiterate that interfaces are like contracts, once implemented, cannot be
modifed. Further, they have to be implemented in full. The logic behind this is that any
amendments made to the interfaces, will disrupt the code when the program is recompiled,
since the class has no mechanism to implement the new changes.

The program stipulated below has nothing to do with interfaces, but it demonstrates the
necessity for coding in the appropriate manner.

a.vb
0ubli. .lass zzz
dim a as yyy
s#ared sub Main()
a ne4 yyy
end sub
end .lass
0ubli. .lass yyy
end .lass

$rror
c:\il\a.vb%4& : error BC303?@: Cannot refer to an instance )e)ber of a class fro)
wit.in a s.ared )et.od or s.ared )e)ber initiali;er wit.out an e0!licit instance of
t.e class.

The above example generates an error because of the word 'shared'. Since the sub Main is
specifed as 'shared', it avoids creating an instance of the zzz class.

But, the object 'a' is an unshared or normal object. To access it, an instance of class zzz is
required. This results in a dichotomy. As a result, instance variables in a sub that is
'shared', cannot be used in spite of instantiating the object 'a'. The other way around works
fne, i.e. we are allowed to use shared variables in 'shared' or instance subs.

Moreover, the above rule does not apply to local variables, i.e. if the dim statement had been
made local or placed inside the sub, no errors would have been generated at all.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim z as zzz
z ne4 zzz()
244258241.doc 1"8 od 272
z.ab.
end sub
sub ab.
dim a as yyy ne4 yyy
dim b as 777 ne4 yyy
dim . as iii ne4 yyy
a.ab.
b.ab.
..ab.
end sub
end .lass
0ubli. .lass yyy
6m0lements 777%iii
0ubli. sub ab. im0lements 777.ab. % iii.ab.
System.Console.Writeline("ab.")
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e
0ubli. inter+a.e iii
sub ab.
end inter+a.e

ut!ut
abc
abc
abc

The above example is a modifcation of the earlier one, wherein the class yyy implements
from two interfaces, viz. iii and xxx, each having a sub abc. This by itself would result in an
error. Therefore, the class yyy has an implements class with sub abc, which contains both
the interface names. In this manner, the compiler is notifed that, sub abc in the class is the
implementation of both the abc subs from the interfaces.

This leads to a single implementation for the sub abc, in the case of both the interfaces.
There is no ambiguity as to which sub abc is to be called. Therefore, no error is visible. An
error is fagged only when the compiler is confused as to which sub is to be called, from
amongst multiple subs of the same ilk.

However, if the class yyy implements the interface jjj containing a sub abc, and then it
writes out the code of the sub abc along with the implements of both the interfaces, a large
number of errors will be generated. This is because the object of type yyy, will now be in a
dilemma as to which sub abc to call, and it would not call the individual interface types.

Thus, the implements can accept multiple interface names that are comma separated. It can
also accept multiple interfaces with sub names, when used along with a sub. What applies
to a sub is also applicable to a function, a property and an event, unless otherwise specifed.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
6m0lements 777
244258241.doc 1"" od 272
0ubli. s#ared sub ab. im0lements 777.ab.
System.Console.Writeline("ab.")
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e

$rror
c:\il\a.vb%=& : error BC30'0': Met.ods or events t.at i)!le)ent interface
)e)bers cannot be declared 'S.ared'.

The above example clearly demonstrates the fact that while implementing an interface
method, the shared attribute cannot be employed. This is because the word 'shared' binds
the sub to the class, and not to the interface. The attributes Overloads, Overrides,
Overridable, Public, Private, Protected, Friend, Protected Friend, MustOverride, Default, and
Static may be used instead.

Using the 'private' access modifer restricts access to the members of the same class.
Individual instances are not permitted to use the member.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e
0ubli. inter+a.e iii
in#erits 777
sub 01r
end inter+a.e

The above example does not generate any error, since we can have an interface iii that
'inherits', but not 'implements' from another interface. Using the keyword 'implements' in
lieu of 'inherits' will generate an error. Thus, any class that implements interface iii, will
then have to implement both the subs named abc and pqr.
a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
im0lements iii
0ubli. sub ab. im0lements iii.ab.
end sub
0ubli. sub 01r im0lements iii.01r
end sub
end .lass
0ubli. inter+a.e 777
sub ab.
end inter+a.e
0ubli. inter+a.e iii
in#erits 777
sub 01r
end inter+a.e
244258241.doc 2## od 272

Implement interface iii will in no way disclose the interfaces that 'iii' has been inherited
from. At the same time, this information is always made available. Thus, while implementing
sub pqr, there is no way to fgure out whether it originates from interface iii or from xxx.
However, changing the implements in sub pqr, from iii.pqr to xxx.pqr, will certainly generate
an error, in spite of it being technically accurate.

When the name of the sub is changed from pqr to abc in the interface iii, the error displayed
below is fashed. This is because two subs with the same name in a class, cannot dwell
together. The problem of duplicity in names has been touched upon earlier.

$rror
c:\il\a.vb%@& : error BC30'>3: 'iii.abc' cannot be i)!le)ented )ore t.an once.

Interfaces are considered to be a useful programming tool, as they separate the defnitions
of objects from their actual implementation. This allows objects to evolve, without incurring
the risk of their breaking down. The whole world of COM or the Component Object Model
lays emphasis on the interaction between binary objects, which can evolve individually over
a period of time, and yet interact seamlessly. This can only happen by employing the concept
of interfaces.

A class implementing an interface, publicly claims to have conformed to certain rules. This
is because, the class defnes the subs declared in the interface. Most importantly, interfaces
have resolved an outstanding predicament of a fragile base class, which occurs when the
base class is modifed.

Interfaces score over classes in their utility, because a class can derive from many
interfaces, and yet have a single implementation.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
im0lements 777
Event eee(;y<al e 9s strin$ ) 6m0lements 777.eee
/un.tion ab. 9s Strin$ 6m0lements 777.ab.
End /un.tion
8ro0erty 01r() 9s 6nte$er 6m0lements 777.01r
Jet
End Jet
Set
End Set
End 8ro0erty
end .lass
6nter+a.e 777
/un.tion ab. 9s Strin$
8ro0erty 01r() 9s 6nte$er
Event eee(a 9s strin$)
End 6nter+a.e

In order to deal with this topic comprehensively, we have created an interface xxx with a
function, a property and an event. The interface is implemented by class yyy. This program
244258241.doc 2#1 od 272
achieves nothing new, other than demonstrating that properties, Events and functions too
can be implemented.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. .lass yyy
im0lements iii
end .lass
0ubli. inter+a.e 777
end inter+a.e
0ubli. inter+a.e iii
in#erits 777 % uuu
end inter+a.e
0ubli. .lass uuu
end .lass

$rror
c:\il\a.vb%##& : error BC303'4: Interface can in.erit onl+ fro) anot.er interface.

In the above example, the interface iii inherits from the interface xxx, as well as, from the
class uuu. Candidly speaking, we didn't expect an error to occur, since we thought that,
whatever worked for a class would also work for an interface.

Man proposes and the Visual Basic.Net compiler disposes! The error indicates the fact that
an interface can only inherit from another interface, and not from a class. It makes sense,
since an interface cannot embody code.

We would have preferred to use the word 'implements' in place of 'inherits' for the sake of
consistency. If you change uuu to an interface, the error disappear.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
0ubli. inter+a.e iii
im0lements uuu
end inter+a.e

$rror
c:\il\a.vb%?& : error BC30?04: State)ent cannot a!!ear wit.in an interface bod+.
$nd of interface assu)ed.

The compiler is very stringent about what is allowed to be placed in an interface. Providing
the wrong keywords such as 'implements', is bound to generate the above generic error.

0ubli. inter+a.e iii

$rror
c:\il\a.vb%#& : error BC302'3: 'Interface' )ust end wit. a )atc.in1 '$nd Interface'.

end inter+a.e

244258241.doc 2#2 od 272
$rror
c:\il\a.vb%#& : error BC302'2: '$nd Interface' )ust be !receded b+ a )atc.in1
'Interface'.

Henceforth, we will show you the above set of matching errors, which occur for every
statement such as sub, interface etc., which contain a matching end statement.

Structures

Before we delve into the innards of a structure, let us attempt the program given below.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
stru.ture sss
end stru.ture

$rror
c:\il\a.vb%'& : error BC302>#: Structure 'sss' )ust contain at least one instance
)e)ber variable or $vent declaration.

The above error message clearly specifes that at least one variable or instance member
should be present within a structure. A class can be empty, but not a structure.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as sss
a ne4 sss
System.Console.Writeline(a.i)
a.i 10
System.Console.Writeline(a.i)
a.i a.i " 100
System.Console.Writeline(a.i)
end sub
end .lass
stru.ture sss
dim i as inte$er
dim j as strin$
end stru.ture

ut!ut
0
#0
##0

In the above program, two variables have been added to the structure defnition. Then, in
the sub main, an object 'a' of type sss has been created. No errors are witnessed because,
akin to a class, a structure may also be used to create new data types. Furthermore, the
keyword of 'new' can be used to instantiate a new instance of a structure. All members of
the object are assigned a default value of zero, when the 'new' keyword is used to create it.

We are allowed to access the members of the structure by using the dot as a separator,
between the name of the structure variable and the structure member. Apart from this, a
244258241.doc 2#3 od 272
new value too can be assigned to the member. However, the member name cannot be used
directly. It has to be preceded by the structure variable and a dot. A structure variable can
be used on both, the left and the right hand side of the 'equal to' sign.

a.vb
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass
stru.ture sss
dim i as inte$er 10
end stru.ture

$rror
c:\il\a.vb%?& : error BC3#04@: Initiali;ers on structure )e)bers are valid onl+ for
constants.

Although there are many concepts that are common between classes and structures, there
still exist a few disparities. For example, an instance variable cannot be initialized in a
structure, whereas, this is possible in a class. Replacing the word 'structure' with 'class' will
wipe away the error thrown earlier.

We now present a few programs that will take a closer look at the similarities and
diferences between structures and classes.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as sss ne4 sss
a.ab.
end sub
end .lass
stru.ture sss
dim i as inte$er
sub ab.
System.Console.WriteLine("#i")
end sub
end stru.ture

ut!ut
.i

The above example reveals that we are permitted to place code in a structure, even though it
is not a very good idea to do so.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as sss ne4 sss
Ea.ab.
end sub
end .lass
stru.ture sss
dim i as inte$er
sub ne4
System.Console.WriteLine("#i")
end sub
244258241.doc 2#4 od 272
end stru.ture

$rror
c:\il\a.vb%@& : error BC30?2@: Structures cannot declare a non3s.ared 'Sub (ew'
wit. no !ara)eters.

The above program bars the use of a 'constructor with no parameters' in a structure.
However, we can have constructors in a structure, provided that they are passed with
parameters. The next program showcases this fact.

a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine(";e$in")
dim a as sss ne4 sss(100)
dim b as sss ne4 sss()
end sub
end .lass
stru.ture sss
dim i as inte$er
sub ne4(j as inte$er)
System.Console.WriteLine(j)
end sub
s#ared sub ne4()
System.Console.WriteLine("S#ared")
end sub
end stru.ture

ut!ut
Be1in
S.ared
#00

The above example clarifes certain concepts about structures and shared constructors. In
the above program, we have created a constructor, which takes an integer as a parameter.
Furthermore, an instance of the sss object is created and passed the number 100 as a
parameter. This leads to it receiving a free constructor with no parameters, since we are
allowed to create an sss object without passing any parameters to 'new'. The member i of the
structure, need not be initialized at all.

Finally, we are allowed to have a constructor with no parameters, provided it is marked as
'shared'. The next example inquires into 'shared' in greater detail.

a.vb
0ubli. .lass zzz
s#ared sub Main()
System.Console.WriteLine(";e$in")
sss.i 10
end sub
end .lass
stru.ture sss
s#ared dim i as inte$er
dim j as inte$er
s#ared sub ne4()
System.Console.WriteLine("S#ared")
end sub
end stru.ture
244258241.doc 2#5 od 272

ut!ut
Be1in
S.ared

A 'shared' constructor is always called before the object gets created. On the other hand, if
the object is not created, the shared constructor never gets called. However, it gets called if a
shared member of the structure is accessed. In the above program, the sss object is not
created at all, but since the shared member i is accessed, the shared constructor gets called.

There ought to be total equality for all in this world!. Based on these lines, a class or
structure can contain either shared or instance members. An instance constructor is
required for the instance members, and a shared constructor is deemed necessary for the
shared members.

The structure must contain at least one instance member, or else, an error crops up. If you
remove the line "dim j as integer", the following error message will be displayed:

$rror
C:\il\a.vb%=& : error BC302>#: Structure 'sss' )ust contain at least one instance
)e)ber variable or $vent declaration.

A short while ago, we had learnt that an instance variable cannot be referred to in a shared
sub, and if this is done, an error is thrown.

A structure is like a class, where diferent types are grouped together into a single entity.
Legend has it that the concept of structures was invented by Kerningham and Ritchie, the
inventors of the C programming language. It was so because, without structures, they were
unable to use the C programming language to write the Unix operating system.
A structure, like a class, is a composite data type, since it contains individual data types.
These individual members in turn, could also be structures and classes. The next example
substantiates this concept.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as ne4 sss
a.j 10
a.5.i !0
System.Console.WriteLine("&0' &1'"% a.j%a.5.i)
end sub
end .lass
stru.ture ttt
dim i as inte$er
end stru.ture
stru.ture sss
dim j as inte$er
dim 5 as ttt
end stru.ture

ut!ut
#0 20

244258241.doc 2#! od 272
In this program, there exists a structure within another structure. The structure ttt or UDT
(user-defned-type), contains an integer member i. This type is now used in another
structure sss, which contains j as an integer member, and k as a ttt type member.

In order to access the members of the structure, the dot is used as a separator between the
structure name and member name. Therefore, to refer to the member j, the structure name
'a' is followed by a dot, which is followed by the member name 'j'. Thus, the resultant
expression is a.j. Similarly, to refer to k, the notation of a.k is used. However, the structure
name k has no meaning, since we are interested in accessing i. Therefore, we follow up k
with another dot and then insert the name of the member i, to arrive at the fnal expression
of a.k.i.

A structure can internally be comprised of many more members. This implies that the
member i could also have been a structure. This structure in turn, could have properties
and events. The access modifers also behave in a similar fashion.

dim a as sss

We have efected only a single change in the above program, and that is, within the dim
statement, we have removed the word 'new', which instantiates the structure. No errors are
encountered here. This is because, like an integer type, there is no essentiality to use the
word 'new' with structures, since it is a value type. It is optional to use the keyword 'new'
with structures.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as ne4 sss
a.j 10
a.5.i !0
a.l.i1 (0
System.Console.WriteLine("&0' &1' &!'"% a.j%a.5.i% a.l.i1)
end sub
end .lass
0ubli. .lass yyy
0ubli. dim i1 as inte$er
end .lass
stru.ture ttt
dim i as inte$er
end stru.ture
stru.ture sss
dim j as inte$er
dim 5 as ttt
dim l as yyy
end stru.ture

$rror
/n.andled $0ce!tion: S+ste).(ullDeference$0ce!tion: b*ect reference not set to
an instance of an ob*ect.
at ;;;.Main%&
In this program, the rules that are implemented on the structure, have also been used on a
class. We introduced one more object l, of type yyy, and a class with one member named i1.
We used the same 'dot within dot' notation to access the member i1, and yet, we got no
compiler error.

244258241.doc 2#7 od 272
This signifes that syntax-wise, a structure and a class are similar. But, when we run the
program, the above exception gets thrown.

The runtime error is generated because the reference type is not instantiated. So, modify the
code to include the following:

a.5.i !0
a.l ne4 yyy
a.l.i1 (0

ut!ut
#0 20 30

Thus, the object l is now instantiated as a new instance of yyy type, by using the keyword
'new'. The compiler should have complained, but it did not.

Structures are automatically allocated memory, and are useful when related information
about a particular entity is to be grouped together.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as ne4 sss
end sub
end .lass
0ubli. .lass yyy
0ubli. dim i1 as inte$er
end .lass
inter+a.e ttt
sub ab.
end inter+a.e
stru.ture sss
im0lements ttt
dim j as inte$er
sub ab. im0lements ttt.ab.
end sub
end stru.ture

A structure is also allowed to implement an interface. Thus, in the above program, the
structure sss is extended to contain an interface ttt implementation. The interface has only
one sub abc, which must be defned in the structure, to avoid an error. Thus, for the
'implements' statement, a structure and a class behave similarly.

The access modifers of a structure consist of the familiar gang of four: public, private,
protected and friend. They work in the same manner as discussed earlier. The default
accessibility for a structure is 'public'.

Every variable created in a structure must have an access modifer specifed for it. Omitting
it will throw an error. The default modifer for a DIM statement in a structure is 'public'. As a
result, the modifer can be skipped when a DIM statement is used in a structure.

The next set of examples will illustrate a major diference between a value type and a
reference type. As indicated earlier, a value type is a simple type, like an integer, or a type
created by a structure. The reference types encompass all the other types.

244258241.doc 2#8 od 272
a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a%b as sss
a.j 10
b a
System.Console.WriteLine(b.j)
b.j 100
System.Console.WriteLine(a.j)
end sub
end .lass
stru.ture sss
dim j as inte$er
end stru.ture

ut!ut
#0
#0

In the Visual Basic.Net program, two objects a and b of value type sss have been created.
Then, the member 'j' of object 'a' is initialized to a value of 10. The members with the object
'b' have not even been touched. On the next line, the entire structure 'b' is initialized to the
structure 'a'.

Consequently, all members of the structure 'b' are assigned the values of the corresponding
members of the structure 'a'. Thus, the member 'j' of structure 'b' gets equated to 10, which
is the equivalent value of the member 'j' in structure 'a'. Therefore, the frst WriteLine
function displays a value of 10.

Continuing with our experiments, we then equate the member j of the structure b to 100,
and then, display the member j from the structure 'a'. However, the value remains 10, thus
displaying no signs of any change, whatsoever. This is because the change was incorporated
in a separate entity 'b', which has no linkages with 'a'. This goes to prove that the value
members of the structure are independent of each other.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a%b as sss
a.j ne4 yyy
a.j.i 10
b a
System.Console.WriteLine(b.j.i)
b.j.i !0
System.Console.WriteLine(a.j.i)
end sub
end .lass
stru.ture sss
0ubli. dim j as yyy
end stru.ture
0ubli. .lass yyy
0ubli. dim i as inte$er
end .lass

ut!ut
#0
20
244258241.doc 2#" od 272

The structure sss is now modifed to contain a reference type variable 'j' of type class yyy.
Then, the variables 'a' and 'b' of type sss are created, using the DIM statement. However,
this does not instantiate the yyy object, since it has to be done explicitly for each of them.

Next, using the structure 'a', the variable j of type yyy is instantiated, and the variable i in
the class is initialized to a value of 10. The member j in the structure b remains un-
initialized, and hence, it does not have any value.

A value type represents an actual value, whereas a reference type stores a number or a
reference to the location where the actual object is stored in memory. If we try to print the
value of the object j, the resultant efect will be that it will actually point to the memory
location where the value of the integer 'i' is stored, and hence, the stored value will get
printed.

On using the new yyy statement, the system allocates some memory to store the members of
the class yyy. If this memory is allocated at the location of 100, the value of the object j will
be 100. So, to access the member i of the class yyy, a two-step procedure is adopted: frstly,
the location at which object begins in memory i.e. 100, is to be accessed. Secondly, from this
memory location of 100, the value of the member i has to be picked up.

Being a two-stage process, it is slower than the value type process that directly contains the
value. Thus, we can retrieve values faster from structure types or value types, rather than
from reference types.

Imagine as to the pace at which the .Net world would crawled, had the integer type also been
made as a reference type !
Like in the previous example, the structure b is equated to the structure a. Doing so assigns
a value of 100 to the member j in structure b. The end result is that the j member, in each
of the two structures, points to the same yyy object.

The WriteLine function displays the member j from object b. The value shown is the same as
in object a. Changing the value of member i using b will now change the value in object a,
since both point to the same yyy object.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a%b as sss
a.j.i 10
b a
System.Console.WriteLine(b.j.i)
b.j.i !0
System.Console.WriteLine(a.j.i)
end sub
end .lass
stru.ture sss
0ubli. dim j as yyy
end stru.ture
stru.ture yyy
0ubli. dim i as inte$er
end stru.ture

ut!ut
244258241.doc 21# od 272
#0
#0

By merely incorporating two small modifcations in the program, the output changes
dramatically. The structure sss now has the member j declared as a value type, and not as a
reference type, since 'class yyy' is changed to 'structure yyy'. Then, the member i of
structure yyy is initialized to 10, using the structure 'a'.

Since it is a structure, there is no need to create a new instance of the structure. Also,
equating the two structures merely results in the assigning of the values to the
corresponding members in the structure. No references are stored. Thus, when the value i is
displayed, it shows a value of 10. Changing its value to 20 does not afect the other
structure, since each of them now behaves as an independent entity. Bear in mind that
internally, integers are also structures.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as sss
a.j 10
ab.(a)
System.Console.WriteLine(a.j)
end sub
s#ared sub ab.(byval s as sss)
s.j 100
end sub
end .lass
0ubli. stru.ture sss
0ubli. dim j as inte$er
end stru.ture

ut!ut
#0

A structure behaves like a value type, even while dealing with parameters. In the above
example, a structure 'a' of type sss has the 'j' member set to 10. Then, the shared sub abc is
called and passed the structure as a parameter.

The sub abc stores the structure in the variable 's', and assigns it the modifer 'byval'. This
modifer ensures that structure 's' is totally disconnected from the structure 'a'. Thus, when
the member j in the sub abc is changed to 100, this change does not get refected in the
original structure. The value of j in sub main remains 10. This has been verifed using the
WriteLine function.



Now, replace the modifer byval with byref in the sub abc as follows:

s#ared sub ab.(byre+ s as sss)

ut!ut
#00

244258241.doc 211 od 272
The modifer byref with the parameter now represents the actual object, and not a copy.
Thus, any changes made to the object 's' will be instantly refected in the object 'a' in the
sub main.

The variable j remains the same in the sub abc, as well as in the sub main. Therefore, if we
change its value to 100, the same value gets refected in the sub main also.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as ne4 sss
a.j 10
ab.(a)
System.Console.WriteLine(a.j)
end sub
s#ared sub ab.(byval s as sss)
s.j 100
end sub
end .lass
0ubli. .lass sss
0ubli. dim j as inte$er
end .lass

ut!ut
#00

In this example, sss is made a class, instead of a structure. Thus, in the DIM statement, it
has to be initialized using the 'new' statement. Then, the j member is set to 10 and the sub
abc is called.

The parameter s, which is provided to the sub, has the modifer of byval. Thus, the value
assigned to object a is also passed on to the object s. Efectively, the object s points to the
same location as the object a.

Thus, any change to the member j in the object s will be refected in the main subroutine.
This is because, s is a reference object, and hence, it points to the same memory location
referenced by the object a. So, for a reference object, it does not make any diference whether
byval or byref is used, since any change made in the object invariably gets refected in the
original.

a.vb
0ubli. .lass zzz
s#ared sub Main()
dim a as ne4 sss
a.j 10
ab.(a)
System.Console.WriteLine(a.j)
end sub
s#ared sub ab.(byval s as sss)
s ne4 sss
s.j 100
end sub
end .lass
0ubli. .lass sss
0ubli. dim j as inte$er
end .lass
244258241.doc 212 od 272

ut!ut
#0

The above example explains the diference between byref and byval in the context of
reference types. We retain the program as before, and now, simply initialize s to a new sss
object. Then, we set the value of the member j to 100.

By using 'new', the parameter 's' that contains a reference to the object 'a' in memory, now
holds a reference to a new sss object. This new sss object is diferent from the object 'a' in
main, as a result of which, any changes made to the object s will not be refected in the
object 'a'. In all, there are two sss objects in memory, viz. 's' and 'a'. The WriteLine function
uses the object 'a' to display the value of 'j'. Hence, the output is shown as 10.

Now, change byval to byref as shown below:

s#ared sub ab.(byre+ s as sss)

ut!ut
#00

The output changes to refect the new value assigned to 'j', because any changes made to the
parameter 's' will simultaneously result in a similar modifcation to the original object 'a'.
Thus, assigning a new memory location to 's' will also change the location of 'a'. As a result
of this, the system loses track of the earlier copy of sss. This explains why WriteLine displays
a value of 100, and not 10.

a.vb
0ubli. stru.ture sss
0ubli. dim j(10) as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
c:\il\a.vb%2& : error BC3#043: Arra+s declared as structure )e)bers cannot be
declared wit. an initial si;e.

In this program we have attempted to create an array in the structure. This is permissible,
as long as the size is not specifed in the array. Since the program mentions the size of the
array, the above error is thrown.

a.vb
0ubli. stru.ture sss
0ubli. dim j() as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
dim a as sss
redim a.j(!)
a.j(0) 10
a.j(1) !0
System.Console.WriteLine(a.j(0) " a.j(1))
244258241.doc 213 od 272
end sub
end .lass

ut!ut
30

The above example places things in the right perspective. The structure sss has an array
variable j of type integer, with no size mentioned.

In Visual Basic.Net, arrays have to be created without specifying the size. This feature
makes it easier to specify the size at a later stage. The 'redim' keyword can be used, along
with the array name and a new size, to modify the dimensions of any array. There is no need
to re-create the array for the variable, since the redim statement performs this job.

Thus, it can be seen that the creation of an array in a structure is a two-step process. The
array j has two members, which are set to the values of 10 and 20 using the dot notation,
respectively. The values are then summed up and displayed.

If we bypass the redim statement, it will lead to non-creation of the array. Thus, the array
member j would be set to nothing. This does not generate any compilation errors, but at run
time, an exception will be thrown. Unlike structures, in the case of classes, the array size
can be specifed at the time of creation of the array. The next program proves this point.

a.vb
0ubli. stru.ture sss
0ubli. dim j as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
dim a(=) as sss
a(0).j 10
a(1).j 100
System.Console.WriteLine(a(0).j " a(1).j)
end sub
end .lass

ut!ut
##0

Any data type can be converted into an array. An array is simply a collection of any type.
The program has an array 'a' containing four sss structures. A value data type needs no
initialization at all. Therefore, the members of a(0), a(1) etc., which actually belong to an
array of structures, now behave like an array of integers.

In all the .Net languages, the syntax of structures and classes looks identical. It is very
difcult to decipher whether the entity is a class or a structure, by merely looking at the
defnition.

A structure, like a class, can contain constructors, methods, properties, felds, events,
constants and enums. Furthermore, it can implement 'interfaces' and have 'shared'
constructors, with or without parameters.

Before we delve on the numerous diferences between structures and classes, we would like
to summarize all the concepts that have been explained earlier in this chapter.
244258241.doc 214 od 272

The .Net world comprises of two basic data types: value types and reference types.
Structures are used to create user-defned value data type, whereas classes are used to
create reference types. There is no other way of creating types in the .Net world. The value
types are simple and fast, compared to the reference types.

All variables created in a function or passed as parameters, are stored in an area of memory
called the 'stack'. This memory gets recycled for every function. Thus, variables and
parameters in the functions lose their values at the end of a function call. The instance
variables are allocated memory in a separate section called the heap area, and they exist till
the program is alive.

A structure is allocated memory on the stack, while classes are placed in the heap area. The
default access modifer for structure members is 'public', whereas, for classes it is the
reverse, i.e. 'private'. This applies only to class variables and constants. Everything else is
like a structure, which has a 'public' modifer. This unusual behaviour is implemented to
maintain compatibility with Visual Basic 6.0.

a.vb
0ubli. stru.ture sss
in#erits ddd
0ubli. dim j as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
c:\il\a.vb%2& : error BC30?2>: Structures cannot .ave 'In.erits' state)ents.

A structure can implement an interface, but it cannot inherit from a class. It is for this
reason that the above error gets generated, since the structure sss inherits from the class
ddd.

A point to be noted here is that, there is no class named ddd in the code. However, the
compiler overlooks this, and throws an error message only in respect of the 'inherit' faw.
This is because, the compiler stops processing as soon as it encounters the frst mistake.

Thus, it is preferable to use structures only for variables, since they cannot receive code
from any class.

a.vb
0ubli. .lass yyy
in#erits sss
end .lass
0ubli. stru.ture sss
0ubli. dim j as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
244258241.doc 215 od 272
c:\il\a.vb%2& : error BC302@@: '+++' cannot in.erit fro) structure 'sss' because 'sss'
is declared '(otIn.eritable'.

The program shows class yyy inheriting from a structure sss. Based on our assumption, this
should work fne. However, we get an error. This is because, the structure has been
implicitly given a modifer of NotInheritable. The next example illustrates the use of the
NotInheritable keyword.

a.vb
0ubli. .lass yyy
in#erits sss
end .lass
0ubli. 3ot6n#eritable .lass sss
end .lass
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
c:\il\a.vb%2& : error BC302@@: '+++' cannot in.erit fro) class 'sss' because 'sss' is
declared '(otIn.eritable' .

The world is full of sly people, who believe that they have absolute right over what belongs to
the others. This feature is visible in programming too. Programmers spend all their time and
efort in creating classes, which they may not want others to use. So, to prevent others from
deriving from the class, the keyword of NotInheritable is used. This is in absolute contrast to
the code-reuse concept, wherein coders openly distribute their code for use by others.

In the above program, class sss is defned to be NotInheritable, thereby disallowing any class
from deriving from it. Since the class yyy derives from it, the rule gets desecrated, resulting
in the above error. By default, the NonInheritable keyword gets added to a structure.

0ubli. 3ot6n#eritable stru.ture sss
0ubli. dim j as inte$er
end stru.ture

$rror
c:\il\a.vb%#& : error BC303@': '(otIn.eritable' is not valid on a Structure
declaration.

We are never allowed to specify the NotInheritable class for a structure. If we do, an error
stating the obvious is shown, because this is simply unacceptable to the compiler.

a.vb
0ubli. stru.ture sss
0rote.ted dim j as inte$er
end stru.ture
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
c:\il\a.vb%2& : error BC3043': Me)bers in a Structure cannot be declared
'8rotected'.
244258241.doc 21! od 272

As a structure cannot be derived from, it makes no sense for a member of a structure to be
declared as 'protected'. To refresh your memory, 'protected' allows only the derived classes to
use the members, and unfortunately, the structure cannot be used as a derived class.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. stru.ture yyy
Event e()
Sub vijay() Handles ..e
End Sub
end stru.ture

$rror
c:\il\a.vb%=& : error BC30=2>: Met.ods declared in structures cannot .andle events.

In structures, event handling imposes too many restrictions. The above error occurs since a
sub 'vijay' in structure yyy handles an event named c.e.

The error clearly mentions the fact that methods in a structure cannot handle events. We do
not get any due to the absence of the object c in the code. Also, the presence of the event e
seems to escape detection.

a.vb
8ubli. Class zzz
Wit#Events b as yyy
S#ared Sub Main()
End Sub
End Class
0ubli. stru.ture yyy
dim a as inte$er
end stru.ture

$rror
c:\il\a.vb%2& : error BC304#3: ',it.$vents' variables cannot be t+!ed as structures.

In order to work with events, a variable in the class containing the event has to be
instantiated. In the above code, since the type passed to the WithEvents clause is a
structure, the compiler complains by displaying an error message. Event handling activities
must be avoided in the case of structures.

Structures implicitly inherit from the class ValueType. However, as said before, we cannot
explicitly specify the 'inherits' keyword with a structure.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. .lass yyy
in#erits System.<alue-y0e
end .lass

244258241.doc 217 od 272
$rror
c:\il\a.vb%?& : error BC300#': In.eritin1 fro) 'S+ste).5alue7+!e' is not valid.

A class cannot derive from ValueType. If this is done, the above error message will be
fagged. A structure has a free constructor, which takes no parameters and initializes all the
members of the structure to their default values. This behaviour cannot be modifed
manually by any programmer.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. stru.ture yyy
dim a as yyy
end stru.ture

$rror
c:\il\a.vb%'& : error BC302@3: Structure '+++' cannot contain an instance of itself:

A member of a structure cannot refer to itself. The above program displays an error message
because, the structure yyy in turn has a member 'a' of type yyy. This is not allowed.
However, this is permissible in a class. This can be proved by modifying the word 'structure'
to 'class'.

This is because, a structure variable is bound to its values, whereas a class variable refers
to the class in memory. Thus, multiple class variables can refer to the same class in
memory. Also, when a statement of 'dim a as sss' is encountered, where sss is a structure
type, the compiler rewrites the code as follows:

dim a as sss
ne4 sss
or
dim a as ne4 sss.

Take your pick. If you write the DIM statement as shown above, the Visual Basic.Net
compiler will be most grateful, since this would have saved it some time. It does not give us
any error either.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as ne4 yyy
a.i 10
a.ab.
a not#in$
a.ab.
End Sub
End Class
0ubli. stru.ture yyy
0ubli. dim i as inte$er
0ubli. sub ab.
System.Console.WriteLine(i)
end sub
end stru.ture

244258241.doc 218 od 272


ut!ut
#0
0

The program starts by creating a structure 'a' using the 'new' keyword, which is optional.
Then, the member i is initialized to 10, and the sub abc is called. Everything works as per
plan, with the sub abc printing the value of i as 10.

After printing the value, the structure variable 'a' is initialized to nothing. This keyword is
special, since it sets all the members of the structure to their default values. Thus, the value
of the integer variable is set to 0. The sub abc cannot be set to any value, since subs cannot
have values. Hence, it is left alone. The result of this operation leads to the display of the
value of i as 0 in abc.

Now re-run the same program again after introducing the following modifcation. Replace
the two instances of the word 'structure' with the word 'class'. Doing so will not generate any
complaints from the compiler. But at run-time, the following exception is thrown:

ut!ut
#0
/n.andled $0ce!tion: S+ste).(ullDeference$0ce!tion: b*ect reference not set to
an instance of an ob*ect.
at ;;;.Main%&

The frst sub does its job of displaying the value of 10. But after initializing the class to
nothing, the exception gets thrown. This is because 'nothing' nullifes all accesses to the
members in the object. Accessing the member i using nothing, is bound to generate an
error.

Thus, setting a structure to nothing resets the members of the structure to a default value.
On the contrary, all the members in a class become inaccessible. The only solution is to use
'new' to create another instance.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as ne4 yyy
dim b as ne4 yyy
System.Console.WriteLine(a is b)
b a
System.Console.WriteLine(a is b)
End Sub
End Class
0ubli. .lass yyy
0ubli. dim i as inte$er
0ubli. sub ab.
System.Console.WriteLine(i)
end sub
end .lass

ut!ut
4alse
7rue
244258241.doc 21" od 272

The above program focuses on classes, and not on structures. The main intention here is to
compare two objects of type yyy, and determine whether they point to the same object or
not. If they do, then they are considered to be equal. To check for equality, the 'is' operator is
used in place of the = operator.

The 'is' operator returns a bool value. In the frst case, since both 'a' and 'b' point to separate
objects in memory, the output shows a bool value of false. Equating object 'b' to 'a' compels
both the objects to point to the same memory location. Hence, the return value is shown as
true.

Now replace the word 'class' with 'structure'. Doing so will generate the following compiler
error:

$rror
c:\il\a.vb%'& : error BC30020: 'Is' re<uires o!erands t.at .ave reference t+!es9 but
t.is o!erand .as t.e value t+!e '+++'.

Structures are considered to be value types, and the operator 'is' acts only on reference
types. Replacing the 'is' operator with the 'equal to' sign for the purpose of comparing two
structures, will result in the following error:

$rror
c:\il\a.vb%'& : error BC304'2: !erator 'I' is not deBned for t+!es '+++' and '+++'.

Thus, the only way to determine the equality of two structures is to compare each and every
member individually. There are no short cuts here. The structure statement can appear
either in a module, or in a namespace, or at the fle level. A structure cannot be created in a
method.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. .lass yyy
0ubli. sub ab.
stru.ture aaa
end stru.ture
end sub
end .lass

$rror
c:\il\a.vb%=& : error BC302>@: State)ent cannot a!!ear wit.in a )et.od bod+. $nd
of )et.od assu)ed.

If we create things out of place, the above generic error gets displayed.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy
a.i 10
a.5.j !0
System.Console.Writeline(a.5.j " a.i)
244258241.doc 22# od 272
End Sub
End Class
0ubli. stru.ture yyy
dim i as inte$er
dim 5 as aaa
stru.ture aaa
dim j as inte$er
end stru.ture
end stru.ture

ut!ut
30

In the structure yyy, we have a variable i of type integer, followed by a variable k of type aaa.
The type aaa is a structure that is created within yyy. This is legally allowed in .Net.

The unfortunate part is that the outer structure cannot directly access the members of the
inner structure. The outer structure has to frst create an object of type aaa, in this case k,
and then access the structure members individually, using the dot notation.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy
a.i 10
a.5 ne4 yyy.aaa
a.5.j !0
System.Console.Writeline(a.5.j " a.i)
End Sub
End Class
0ubli. stru.ture yyy
dim i as inte$er
dim 5 as aaa
.lass aaa
0ubli. dim j as inte$er
end .lass
end stru.ture

ut!ut
30
Similar to a structure, a class too can be created inside a structure, but with a few
modifcations and additions. That is, the instance members of the class, which are 'private'
by default, have to be modifed to 'public'.

This is the singular change required in the structure yyy. The major change occurs in the
sub main, where an instance of class aaa has to be created. If we do not create it, an
exception will be thrown at run time. The name of the class cannot be referred to as 'aaa';
instead, it has to be referred to as yyy.aaa, since it resides in the structure.

Thus, a new instance of the object aaa is created by using yyy.aaa with the 'new' keyword.
The object k is then initialized to this value. The statement of 'dim k as new aaa' is not
allowed for defning k because, the 'new' keyword is not allowed within structures. The class
aaa can also be referred to as an inner class or a nested class.

A structure with the access modifer of 'friend' can be used from anywhere in the same
assembly. Every member of the structure must be explicitly declared. Thus, all variables
244258241.doc 221 od 272
must either use DIM or one of the access modifers of 'public', 'private' or 'friend'. The
'protected' modifer is not allowed, as explained earlier.

A structure could have properties, constants and procedures, but the absence of a non-
shared variable will compel the compiler to show an error. There are no scoping rules for a
structure. Thus, all the members are visible to each other. A structure,as well as a class,
facilitates the construction of user-defned data structures.

Enumerators

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as aaa
System.Console.WriteLine("&0' &1'"%a.a1%C6nt(a.a!))
End Sub
End Class
0ubli. enum aaa
a1
a!
end enum

ut!ut
a# #

The above example explains the concept of an enum, which is a short form for 'enumerator'.
An enum is very similar to a structure or a class, since it merely creates a type. An enum
type called aaa is created, containing two members of a1 and a2.

To display the member, the dot notation is used as follows: a.a1. This is similar to the
notation used in structures. In the WriteLine function, if we use the name a.a2, it returns
the value of 'a2'. However, if you use the CInt function with the name, it returns the number
1 instead. We will cater to conversion functions such as CInt in greater detail later.

The CInt function converts the parameter given to it into a number or integer. In an enum
type, the frst member is assigned a value of 0, the second one is assigned a value of 1, and
so on. An enum object allows the use of the member name instead of a number, thus
making the programs more readable.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. enum aaa
end enum

$rror
c:\il\a.vb%'& : error BC302>0: $nu) 'aaa' )ust contain at least one )e)ber.

The enum follows the rules of a structure, wherein, it requires at least one member.


a.vb
8ubli. Class zzz
244258241.doc 222 od 272
S#ared Sub Main()
dim a as ne4 aaa
System.Console.WriteLine("&0' &1' &!'"%C6nt(a.red)%C6nt(a.blue)%C6nt(a.$reen))
End Sub
End Class
0ubli. enum aaa
red
blue 100
$reen
end enum

ut!ut
0 #00 #0#

An enum object, such as a structure, does not need the 'new' keyword to instantiate it.
However, if we use it, no error is generated. Enums are used to document numbers. For
example, it is much more intuitive to use a.green, instead of a number.

The default values assigned to each and every member of the enum can be changed easily.
Thus, the member red takes the default of 0, whereas the value of member blue is changed
to 100. This results in green, which is the next member, being assigned a value of 101.

The Enum type inherits from the System.Enum class, and is normally used to represent a
small set of numeric values using names.

The default data type for the numbers is 'integer', which can be changed by using the 'as'
clause. For example, "public enum aaa as long" will change the default type to 'long'.
Alternatively, the type can be changed to 'byte short' etc.

These types difer from each other in terms of the range of numbers that they can store. The
scope of the members is restricted to the enum defnition. Outside the enum, every member
has to be qualifed by the name of the enum object.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
enum aaa as 2ouble
$reen
end enum

$rror
c:\il\a.vb%'& : error BC30?'0: $nu)s )ust be declared as 'B+te'9 'S.ort'9 'Inte1er' or
'-on1'.

The above error message clearly identifes the four data types that an enum type can
possess. Types such as Double are strictly prohibited.

a.vb
8ubli. Class zzz
S#ared Sub Main()
System.Console.WriteLine("&0' &1' &!'"%C6nt(aaa.red)%C6nt(aaa.blue)%C6nt(aaa.$reen))
End Sub
End Class
0ubli. enum aaa as lon$
244258241.doc 223 od 272
red
blue 100
$reen
end enum

ut!ut
0 #00 #0#

There is no need to create an object of type enum, in order to use an enum member. This
point has been demonstrated in the program above. The name of the enum aaa is sufcient
to access the members of red, green and blue. This is the preferred method while using
enums.


a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
enum aaa as lon$
$reen
0ubli. red
end enum

$rror
c:\il\a.vb%=& : error BC30?#@: State)ent cannot a!!ear wit.in an $nu) bod+. $nd
of $nu) assu)ed.

An enum member cannot have any access modifer associated with it. The default access
assigned to each of the members is 'public'. The error message is generic in the sense that,
whenever we place something inappropriate in an enum, the above error message is
displayed.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
enum aaa as byte
$reen
red 1000
end enum

$rror
c:\il\a.vb%=& : error BC3043@: Constant e0!ression not re!resentable in t+!e 'B+te'.

In the above program, the enum type is declared to contain Bytes. Since a byte value cannot
exceed beyond 255, the above error gets reported. The value of 1000 exceeds the range of
the byte type, thus causing the error.


a.vb
8ubli. Class zzz
s#ared 0ubli. dim i as inte$er
S#ared Sub Main()
End Sub
End Class
244258241.doc 224 od 272
enum aaa as byte
$reen
red zzz.i
end enum

$rror
c:\il\a.vb%>& : error BC300'@: Constant e0!ression is re<uired.

The value of an enum has to be a constant, which means that the value must be available at
compile time. Initializing the member red to zzz.i would have worked fne if 'i' had a constant
value. But since 'i' is a static variable in the class zzz, its value is likely to be changed in the
constructor. This ambiguity is not acceptable. Hence, the error message is generated. The
enum members have to be assigned values that are constants.

a.vb
8ubli. Class zzz
S#ared Sub Main()
System.Console.WriteLine("&0' &1' &!'" % C6nt(aaa.$reen)%C6nt(aaa.red)%C6nt(aaa.blue))
End Sub
End Class
enum aaa as lon$
$reen 1
red $reen
blue red
end enum

ut!ut
# # #

Members of the enum can be assigned the same values. In the program, the member green
has been given a value of 1. Then, the member red is equated to green, resulting in the value
of 1 being assigned to red also. Finally, blue is assigned the value of red, which again is 1.
Therefore, fnally, the value contained in all the three members is 1. The example also proves
the fact that one member in an enum can be initialized to another member.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
enum aaa as lon$
$reen red
red $reen
end enum

$rror
c:\il\a.vb%=& : error BC30'00: Constant '1reen' cannot de!end on its own value.

We may slump at the wheel, but the compiler does not. The above example is a classical
case of a 'circular reference'. The member green depends upon the member red, which in
turn depends on the member green. The Visual Basic.Net compiler detects such circular
references and gives the above error.

enum aaa as lon$
$reen red
red
244258241.doc 225 od 272
end enum

The above example generates the same error because the member green depends upon the
member red explicitly, while the member red internally depends upon the member green,
since it simply increments the value of member green by 1.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as inte$er 1
i+ a aaa.$reen t#en
System.Console.WriteLine("#i")
end i+
End Sub
End Class
enum aaa
$reen 1
end enum

ut!ut
.i

Even though an enum is a type by itself, we are allowed to compare an enum with a number.
The 'if' statement results in true, because the value of green is 1, and 'a' is declared with a
value of 1. As we mentioned earlier, enums are used, to avoid using numbers. An enum is a
symbolic name for a set of values. It does add any overhead to the program, since the
compiler replaces the enum values with the actual values at compile time.

The .Net world has plenty of enums, which are implemented in various programs.

a.vb
8ubli. Class zzz
enum aaa
$reen
end enum
S#ared Sub Main()
End Sub
End Class

An enum data structure can be declared in a source fle, or in a module, or in a structure,
or even in a class, as the above example shows. However, it cannot be placed in a procedure.
An enum data type has all the rights of a data type created by a class, and hence, it can be
used as a type in a function parameter, as well as a parameter to a constructor.


Class Statements

a.vb
dim a as inte$er
0ubli. .lass zzz
s#ared sub Main()
end sub
end .lass

$rror
c:\il\a.vb%#& : error BC3000#: State)ent is not valid in a na)es!ace.
244258241.doc 22! od 272

Our primary focus is on the class, because everything in Visual Basic.Net must be placed in
a class. Variables, subs etc cannot be created outside a class. The above error will be
generated whenever an entity is created outside a class. There are very few entities that can
be created outside a class; however, they still have to be placed within a namespace.

Let us now look at the modifers that can be used with the DIM statement when creating an
object or a variable.

a.vb
0ubli. .lass zzz
dim readonly a as inte$er
s#ared sub Main()
dim z as zzz ne4 zzz
z.ab.
end sub
sub ab.
a 10
end sub
end .lass

$rror
C:\il\a.vb%>& : error BC300?4: 'Deadnl+' variable cannot be t.e tar1et of an
assi1n)ent.


The ReadOnly modifer gives only read permission to the variable; the variable cannot be
written to. Thus, attempting to change the value of the variable in the sub abc would be
asking for trouble.

a.vb
0ubli. .lass zzz
dim readonly a as inte$er !0
s#ared sub Main()
dim z as zzz ne4 zzz
z.ab.
end sub
sub ab.
System.Console.WriteLine(a)
end sub
end .lass

ut!ut
20

The above example depicts the correct approach while using readonly variables. A ReadOnly
variable can be initialized at the time of creation. Thereafter, no changes to it are permitted.
Its value can be used, but not changed.

However, there is one exception to this rule. The value of a readonly variable can be changed
in the constructor or the sub 'new', as shown below. Add the following lines of code before
the end class. This results in the value of 'a' being displayed as 10, and not 20.

sub ne4
a 10
end sub
244258241.doc 227 od 272

The DIM statement can be used at the module, class, structure, procedure or block level. In
other words, other than certain exceptions, like we have shown above, a DIM statement can
be used anywhere in the program.

Similar to the DIM statement, the access modifers too can be used anywhere in the code.
a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as ne4 zzz
dim i as inte$er 1
4#ile ( i * , )
a.ab.
i i " 1
end 4#ile
End Sub
sub ab.
stati. dim j as inte$er 10
j j " 1
System.Console.Write("&0' "% j)
end sub
End Class

ut!ut
## #2 #3 #4 #'

Removal of the keyword 'static' from the DIM statement in the above program generates the
following output:

ut!ut
## ## ## ## ##

Earlier, we had briefy mentioned that a variable created in a sub remains alive as long as
the sub is alive. The moment the sub fnishes execution, the variables created in it become
inaccessible, since they cease to exist.

The sub abc is called 5 times, using the loop construct. Within the sub, a variable j is
created using the modifer of 'static', thus making 'j' a static variable.

A static variable acts as an instance variable to the extent that, it retains its value across
function invocations. However, it cannot be accessed outside the sub that it is created in.
Thus, the variable j is initialized to 10 only when the DIM statement is encountered for the
frst time.
Had it not been a static variable, the sub would have had to initialize the variable j to 10
every time. However, since it has been declared as static, succeeding calls to the function
ignore the DIM statement. This is why it is created only once, and thereafter, it retains its
value.

a.vb
8ubli. Class zzz
stati. a as inte$er
S#ared Sub Main()
End Sub
End Class

244258241.doc 228 od 272
$rror
c:\il\a.vb%2& : error BC3023': 'Static' is not valid on a )e)ber variable declaration.

Static variables can be placed in a shared or non-shared method, but they cannot be
created outside a procedure, at the class or module level. This error is obvious, since static
variables are instance variables, with local access.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
stati. sub ab.
end sub
End Class

$rror
c:\il\a.vb%4& : error BC30>#0: Met.ods cannot be declared 'Static'.

Methods obviously cannot be declared static, since the concept of static applies to variables
only.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. stru.ture aaa
dim j as inte$er
sub ab.
stati. i as inte$er
end sub
end stru.ture

$rror
c:\il\a.vb%>& : error BC3#400: -ocal variables wit.in )et.ods of structures cannot
be declared 'Static'.

An additional restriction on static variables is that, they cannot be created within
procedures in a structure. Methods are not preferred entities in a structure.

a.vb
8ubli. Class zzz
S#ared Sub Main()
stati. i as inte$er
stati. i as inte$er
End Sub
End Class

$rror
c:\il\a.vb%4& : error BC3#40#: Static local variable 'i' is alread+ declared.

We are obviously are not allowed to create entities of any type having the same name. This
rule applies to static variables also. The simple reason for this is that the variables bearing
the same names would confuse the Visual Basic.Net compiler, since it would not be able to
identify the variable that it has to use.

244258241.doc 22" od 272
a.vb
8ubli. Class zzz
S#ared Sub Main()
dim i as inte$er
dim i as inte$er
End Sub
End Class

$rror
c:\il\a.vb%4& : error BC302>>: -ocal variable 'i' is alread+ declared in t.e current
bloc:.

The rule pertaining to duplicate names applies to local and instance variables also, but the
error number and message that is generated are very diferent from those generated for
duplicate static variables.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. stru.ture zzz
dim i as inte$er
end stru.ture

$rror
c:\il\a.vb%#& : error BC30#=@: class ';;;' and structure ';;;' conEict in na)es!ace
'K6efault>'.

Structures and classes too cannot bear identical names, as they both share the same
namespace. Here, the meaning of the word namespace is very diferent from what we have
learnt earlier.

Each time a type is created, Visual Basic.Net stores the type in a specifc area in memory. As
it stores the types created by a class and a structure in the same area of memory, the above
error gets reported.

However, a class and a variable in the class can both have the same name, since the class
names and the members of a class are stored in diferent namespaces. On the other hand,
within a class, the felds and methods cannot have identical names, since all the members
of the class are stored in the same namespace.


a.vb
8ubli. Class zzz
S#ared Sub Main()
s#ared dim zzz as zzz
End Sub
End Class

$rror
c:\il\a.vb%3& : error BC3024=: 'S.ared' is not valid on a local variable declaration.

Coming back to the concept of shared variables, since they belong to a class and not a
function, they cannot be created in a function.

244258241.doc 23# od 272
Local variables are not visible outside of a function, and hence, the rest of the class
members cannot access local variables.

The above error message is generic, and it shows up whenever a modifer is applied to a
local variable that is not applicable. There are certain combinations like 'static' and 'shared',
which obviously are incompatible with each other, since 'static' is applied to local variables,
whereas 'shared' is applied to instance variables.

a.vb
8ubli. Class zzz
dim i as inte$er
S#ared Sub Main()
dim a as ne4 zzz
a.i 100
a.ab.
System.Console.WriteLine("9+ter ab. &0'"%a.i)
a.01r
System.Console.WriteLine("9+ter 01r &0'"%a.i)
End Sub
sub ab.
dim i as inte$er
i 10
System.Console.WriteLine("ab. &0'"%i)
end sub
sub 01r
ab.
System.Console.WriteLine("01r &0'"%i)
i !0
end sub
End Class

ut!ut
abc #0
After abc #00
abc #0
!<r #00
After !<r 20

The above example showcases a new concept called 'shadowing' a variable. An integer
variable i is created, with its value set to 100. Then, the sub abc is called. In the sub, one
more variable named i is created with the value of 10. When the value is displayed in the
sub, it shows 10, as expected.

On quitting the sub abc, in order to display the value of i in sub main, the instance 'a' is
used as a prefx, since the sub is 'shared'. The value of i still remains as 100. This goes to
prove that the two variables named i are diferent. This concept is termed as shadowing,
where the outer variable i, or the instance variable i gets shadowed by the inner variable i,
since they both have same names.

Then, the sub pqr is called, which calls the sub abc again. As before, the sub abc recreates
the variable i and sets it to a value of 10. Thus, the value of i in abc is shown as 10.
However, when we re-display the value of i in sub pqr, before changing its value to 20, the
value shown is 100.

244258241.doc 231 od 272
After assigning a new value of 20, the sub pqr quits out to the WriteLine statement in the
shared sub Main. The value displayed is 20. This proves that the i in sub pqr is the instance
variable, whereas, the i in sub abc is a local variable.

a.vb
8ubli. Class zzz
dim i as inte$er
S#ared Sub Main()
End Sub
sub ab.
i 10
dim i as inte$er
end sub
End Class

$rror
c:\il\a.vb%?& : error BC32000: -ocal variable 'i' cannot be referred to before it is
declared.

Even though there exists an instance variable i, the statement of i=10 in the sub abc gives
an error, saying that i has not been declared. This occurs in spite of following up the
statement with the DIM statement. On placing the DIM statement in comments, the error
vanishes, since instance variables can be easily accessed in functions.

The error occurs because till it reaches the DIM statement, the compiler believes that the
variable used is an instance variable. However, after recognizing the variable as a local
variable, on encountering the DIM statement, it ignores the instance variable. It also fags
an error on the initialization statement, since the variable has been created after it. If you
move the DIM statement of the sub above the initialization, everything works well.

Thus, shadowing hides the variable with the same name, and prevents the shadowed
variable from being referenced. There are two ways that we can shadow a variable:
The frst method is the one we have seen above, where we shadow using the concept
of 'scoping'. The variable with the narrower scope wins.
The second and more important way of shadowing is using the 'shadows' keyword.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy
dim b as 777
a ne4 777
b ne4 777
System.Console.WriteLine("&0' &1'"%a.i%b.i)
End Sub
End Class
0ubli. .lass yyy
0ubli. dim i as inte$er 10
end .lass
0ubli. .lass 777
in#erits yyy
0ubli. dim i as strin$ "#i"
end .lass

,arnin1
244258241.doc 232 od 272
c:\il\a.vb%#'& : warnin1 BC40004: variable 'i' conEicts wit. variable 'i' in t.e base
class '+++' and so s.ould be declared 'S.adows'.

ut!ut
#0 .i

In the above example, the class yyy has a member i of type integer. The class xxx inherits
from the class yyy and creates a member i of type string. At this stage, the compiler gives a
warning, and not an error.

The compiler very decently points out the fact that both variables are named i. Therefore,
the one located in the derived class should use the modifer of 'shadows'.

By adding the modifer 'shadows' to the variable i in the DIM statement, the warning
disappears.

0ubli. .lass 777
in#erits yyy
s#ado4s 0ubli. dim i as inte$er 100
end .lass


The same warning would also be issued, if the data types of the variables are identical.

0ubli. .lass 777
in#erits yyy
sub i
end sub
end .lass

$rror
c:\il\a.vb%#0& : warnin1 BC40004: sub 'i' conEicts wit. variable 'i' in t.e base class
'+++' and so s.ould be declared 'S.adows'.

The compiler dispatches a similar warning when the class xxx has a sub called i, instead of
variable called i. It is advisable not to create any entity in the derived class having an
identical name to an entity in the base class.

Thus, the 'shadows' modifer serves the purpose of informing the compiler about an
identically named programming element in the base class. The 'shadows' keyword also
prevents the derived class from accessing the base class member.

The 'shadows' modifer can only be used at the module, namespace or fle level. This implies
that we can use it in a source fle, module, class or structure, but not in a procedure. Since
shadows cannot be used inside a procedure, the modifers of 'static' and 'shadows' cannot be
used at the same time.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
0ubli. .lass yyy
s#ado4s 0ubli. dim i as inte$er 10
end .lass
244258241.doc 233 od 272

Since shadows only emits a warning, even though it hides something from the base class, in
the above case, we shadow the variable i in the class yyy. There is no variable i in the base
class that the class yyy derives from. Hence, the compiler does not generate any alarm.

We are allowed to redefne any base class element that we like. There is a major diference
between 'shadowing' and 'overriding', both of which apply to derived classes.

When we override a procedure, we make sure that the new procedure gets called, but the
procedure of calling it remains the same.

In shadowing, we protect the base class from being modifed, by having a similar member in
the base class later. The redefned element and defning element can be of any type, but in
'overriding', the redefned element must be a procedure and the refning element must be a
procedure that has the same calling sequence.

The signature consists of the element type (i.e. function, sub or property, name, argument
list) and the return type.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
.lass yyy
6n#erits 777
Averrides sub ab.( i as inte$er )
end sub
end .lass
.lass 777
Averridable sub ab.
end sub
end .lass

$rror
c:\il\a.vb%=& : error BC302>4: sub 'abc' cannot be declared 'verrides' because it
does not override a sub in a base class.



,arnin1
c:\il\a.vb%=& : warnin1 BC40003: sub 'abc' s.adows an overloadable )e)ber
declared in t.e base class '000'. If +ou want to overload t.e base )et.od9 t.is
)et.od )ust be declared 'verloads'.

There is one error and one warning above. The error is clear, in that, we can only override a
sub abc if there is a sub abc with the same integer as a parameter. Here, this is not the
case, and hence, the error is generated.

This error occurs because, in the base class xxx, the sub abc does not have any parameters.
Thus, there is nothing to override. The warning is not important, as the keyword 'overloads'
is optional, and it is a hint to the Visual Basic.Net compiler that we are overloading a
procedure.

a.vb
244258241.doc 234 od 272
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class
.lass yyy
6n#erits 777
Averrides +un.tion ab. as inte$er
end +un.tion
end .lass
.lass 777
Averridable sub ab.
end sub
end .lass

$rror
c:\il\a.vb%=& : error BC3043=: '8ublic verrides 4unction abc%& As Inte1er' cannot
override '8ublic verridable Sub abc%&' because t.e+ diFer b+ t.eir return t+!es.

In the class yyy, we now change the sub abc to a function abc. This gives us an error
because as explained above, we are allowed to change the types when we shadow, but not
when we override.
The keyword shadows is recommended in the derived class, which means that it is optional.
If the Overrides keyword is not present, the default is shadows. In the Overriding case, the
keyword 'overridable' is mandatory in the base class, and the keyword 'overrides' is a must
in the derived class.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as yyy
dim b as 777
dim . as vvv
a ne4 vvv
b ne4 vvv
b.ab.
. ne4 vvv
..ab.
System.Console.WriteLine("&0' &1' &!'"%a.i%b.i%..i)
End Sub
End Class
0ubli. .lass yyy
0ubli. dim i as inte$er 10
end .lass
0ubli. .lass 777
in#erits yyy
s#ado4s 0rivate dim i as strin$ "#i"
sub ab.
System.Console.WriteLine("ab. &0' "%i)
end sub
end .lass
0ubli. .lass vvv
in#erits 777
end .lass

ut!ut
abc .i
abc .i
#0 #0 #0
244258241.doc 235 od 272


We start with a class yyy, which has a public integer variable i. The important point is the
use of the modifer 'public'. Then, the class xxx that derives from class yyy also has an
integer i that is 'private'. This means that only the members of the class yyy, like the sub
abc, are allowed to access the integer i.

This integer i is associated with the 'shadows' keyword, to get rid of the warning message
that gets displayed. Finally, we have a class vvv that derives from the class yyy. It has no
members. We create three objects a, b and c of types yyy, xxx and vvv, respectively. Then, we
initialize them to a derived vvv object.

We call the sub abc only from the b and c objects, since the class yyy has the sub abc. In
this sub, the integer i is the string type created as a private variable. When we display the
member i from the yyy object 'a', the integer i gets displayed.

When we display the member i from the xxx class, since the member i is private, we are only
allowed to reference the member i from the class yyy. The 'private' modifer overshadows the
'shadows' keyword. In the class vvv, the i that is visible is the integer i from the class yyy.

Thus, when we shadow an element, it is also shadowed in the derived class. If we remove
the private keyword, and make it public in class xxx, the class vvv will see the value of i as
"hi" and not as 10. During overriding, the overriding element is inherited by further derived
classes, and the overridden element is overridden yet again.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim b as 777
b ne4 777
b.ab.
End Sub
End Class
0ubli. .lass yyy
0ubli. dim i as inte$er 10
end .lass
0ubli. .lass 777
in#erits yyy
s#ado4s 0ubli. dim i as strin$ "#i"
sub ab.
System.Console.WriteLine("&0' &1'"%Me.i%My;ase.i)
end sub
end .lass

ut!ut
.i #0

Nothing prevents us from accessing the shadowed member, by using the MyBase keyword. It
allows us to access members from the base class, whether they are shadowed or not. The Me
keyword permits us to access the current class, and as mentioned earlier, it is optional.

Thus, in the world of shadowing, we are re-declaring a member. When we shadow, as seen in
the above example, we are not removing a member. Instead, we are simply hiding it.

a.vb
244258241.doc 23! od 272
.lass zzz
s#ared Sub Main()
2im a 9s 777 3e4 777()
a.01r(1%!)
a.01r()
a.01r(10)
End Sub
End .lass
0ubli. Class yyy
Sub 01r()
End Sub
Sub 01r(i 9s 6nte$er)
End Sub
End Class
0ubli. Class 777
6n#erits yyy
S#ado4s Sub 01r(i 9s 6nte$er % j as inte$er)
End Sub
End Class
$rror
c:\il\a.vb%'& : error BC304'': Ar1u)ent not s!eciBed for !ara)eter 'i' of '8ublic
S.adows Sub !<r%i As Inte1er9 * As Inte1er&'.

The above example generates four errors. We start by declaring the class yyy to have two
subs, both named pqr, with zero and one parameter, respectively. Then, we come to class
xxx, which inherits from class yyy and brings in one sub abc that accepts two parameters.

The shadows keyword ensures that the subs created in the base class are hidden. This
hides the subs abc, having zero and one parameter. Thus, the compiler sees only one sub in
the class yyy, which has two parameters.

In the sub main, the call of the sub abc with two parameters gives no errors, but the other
two calls of the sub abc are erroneous, due to the fact that the shadows keyword conceals
the other two subs.

If we remove the shadows keyword, we do not get any error, since the class xxx now contains
three abc subs, i.e. two from the class yyy, and one from the class xxx. If we add the
keyword 'overloads', no error is generated, even though this sub abc is not overloaded with
two parameters.

a.vb
.lass zzz
s#ared Sub Main()
2im a 9s 777 3e4 777()
a.01r(10)
a.01r()
End Sub
End .lass
0ubli. Class yyy
Sub 01r()
End Sub
Sub 01r(i 9s 6nte$er)
End Sub
End Class
0ubli. Class 777
6n#erits yyy
Averloads Sub 01r(i 9s 6nte$er )
244258241.doc 237 od 272
End Sub
End Class

The above example reiterates what we have said above. The class yyy now has two subs abc.
The frst is the sub abc with no parameters, from the class yyy, and the other is from the
class xxx with one parameter. This overrides the one from the class yyy. If we change the
'overloads' keyword to 'shadows', we get the error given below:

$rror
c:\il\a.vb%'& : error BC304'': Ar1u)ent not s!eciBed for !ara)eter 'i' of '8ublic
S.adows Sub !<r%i As Inte1er&'.

This error occurs since the 'shadows' keyword hides the two abc subs, and we are left with
only one abc sub with an integer as a parameter. As mentioned earlier, shadows is the
default.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class yyy
0ubli. dim i as inte$er
End Class
0ubli. Class 777
in#erits yyy
s#ado4s 0ubli. dim i as inte$er
End Class
0ubli. Class vvv
in#erits 777
0ubli. dim i as inte$er
End Class



$rror
c:\il\a.vb%#4& : warnin1 BC40004: variable 'i' conEicts wit. variable 'i' in t.e base
class '000' and so s.ould be declared 'S.adows'.

We have three classes yyy that have one integer i, the class xxx that derives from class yyy
and has a integer i, and fnally, the class vvv, which in turn derives from the class xxx, It
also has one integer i.
The class xxx uses the 'shadows' keyword on the defnition of the variable i, to stop the
compiler from emitting the warning. In the class vvv, while creating the variable i, we have
used the 'shadow' keyword. Thus, the compiler gives us a warning, since the 'shadow'
keyword does not pass on to the derived classes by default. We have to explicitly mention it,
in order to avoid the warning. No error is generated.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class yyy
s#ado4s overloads sub ab.
end sub
244258241.doc 238 od 272
End Class

$rror
c:\il\a.vb%?& : error BC3#40>: 'verloads' and 'S.adows' cannot be co)bined.

We cannot combine 'shadow' and 'overloads', as they are mutually exclusive. The shadow
concept hides things, whereas, overloads allows us to us override something. If you
remember, earlier we had encountered the error message that overrides and shadows cannot
be combined. Thus, we once again have a generic error message.

a.vb
.lass zzz
s#ared Sub Main()
2im a 9s aaa ne4 ddd
2im b 9s bbb ne4 ddd
2im . 9s ... ne4 ddd
2im d 9s ddd ne4 ddd
a.ab.()
b.ab.()
..ab.()
d.ab.()
End Sub
End .lass
Class aaa
8ubli. Averridable Sub ab.()
System.Console.WriteLine("aaa")
End Sub
End Class
Class bbb
6n#erits aaa
8ubli. Averrides Sub ab.()
System.Console.WriteLine("bbb")
End Sub
End Class
Class ...
6n#erits bbb
8ubli. Averrides Sub ab.()
System.Console.WriteLine("...")
End Sub
End Class
Class ddd
6n#erits ...
8ubli. Averrides Sub ab.()
System.Console.WriteLine("ddd")
End Sub
End Class

Aut0ut
ddd
ddd
ddd
ddd


We start by having four classes aaa, bbb, ccc and ddd, which have one sub abc. Then, we
create four objects a,b, c and d of types aaa, bbb, ccc and ddd, respectively. Then, we
initialize all of them to an instance of class ddd.

244258241.doc 23" od 272
If the compile type and run time type are the same, it is very easy to fgure out as to which
function has been called. The dilemma is caused when the compile time data type is
diferent from the run time data type, as in the above example.

If we call the sub abc using any of the objects, let us try to decipher as to which sub abc
would be called. The sub abc in class aaa is overridable, which means that only the derived
classes have permission to override this sub by the class aaa. The derived classes bbb, ccc
and ddd override this sub. Hence, in all the cases, the sub abc will be called from class ddd.
This was explained earlier, but not using four classes, as we have done in the above
example.

It is mandatory for us to specify the overrides for both the classes bbb and ccc, or else, an
error will result. This is because, in the class aaa, we cannot specify the keyword overrides,
as we have already specifed the keyword overridable.

Class aaa
8ubli. Averridable Averrides Sub ab.()
System.Console.WriteLine("aaa")
End Sub
End Class

$rror
c:\il\a.vb%#4& : error BC30=30: Met.ods declared 'verrides' cannot be declared
'verridable' because t.e+ are i)!licitl+ overridable.

Just to prove our point, we added the keyword 'overrides' to the class aaa in sub abc, and
obviously obtained the above error. The error boldly proclaims that when we make a sub
overridable, we are also overriding it by default. Then, we remove the 'overrides' keyword
from the sub abc class aaa.

It is not mandatory for the sub abc in class ddd to have the overrides keyword, as we may
not want to override the sub abc from the base class. Technically speaking, the class aaa
uses the 'overridable' keyword, and the classes bbb, ccc and ddd do not have to contain the
keyword 'overrides'.

However, if the class bbb decides to have the keyword 'overrides', the classes ccc and ddd
can ignore it. However, if the class ccc uses the 'overrides' keyword, then the class bbb has
to also contain the 'override' keyword, whereas the class ddd does not have to.

Thus, if the derived class uses the 'override' keyword, all the base classes must also use the
'override' keyword or the 'overridable' keyword. We shall explain this shortly.

a.vb
Class ...
6n#erits bbb
0ubli. overridable Sub ab.()
System.Console.WriteLine("...")
End Sub
End Class

,arnin1
c:\il\a.vb%2?& : warnin1 BC4000': sub 'abc' s.adows an overridable )et.od in a
base class. 7o override t.e base )et.od9 t.is )et.od )ust be declared
'verrides'.
244258241.doc 24# od 272

ut!ut
bbb
bbb
ddd
ddd

The overrides keyword for the sub abc in class ccc has been replaced by the overridable
keyword. By doing this, we not only receive a warning from the compiler, but the output also
changes dramatically. To get rid of the warning, add the shadows keyword to the sub abc in
class ccc as follows:
0ubli. s#ado4s overridable Sub ab.()
The 'shadows' keyword normally does not display any errors, but only generates pesky
warnings. Let us understand the output of the programs above. The frst two objects a and
b call the sub abc from the class bbb, and in the last two cases, the c and d objects call the
sub abc from the class ddd.

So far, we have learnt that we can shadow inherited methods or the methods from a base
class. Thus, in the above case, we have four classes that have the same method signature
for the method abc. The Visual Basic.Net complier has no problems here, as only one abc
sub will be visible, which is the last derived one.

The class bbb overrides the sub abc from the class aaa. The class ccc creates a new sub
abc, which has nothing to do with the sub abc from the class bbb. Thus, for the classes aaa
and bbb, there will be one sub, and for classes ccc and ddd, there will be a diferent sub.

The overridable keyword thus behaves like the Great Wall of China, by giving two diferent
abc subs in the classes aaa and ccc. The sub in class aaa class is overridden by the one in
class bbb, and the sub in class ccc is overridden by the one in class ddd. It is not possible
for the class ddd to override the sub of class aaa, since its scope is limited to class ccc only.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
Class aaa
8ubli. Sub ab.()
End Sub
0rivate Sub 01r()
End Sub
End Class
Class bbb
6n#erits aaa
8ubli. Sub ab.()
End Sub
0ubli. Sub 01r()
End Sub
End Class

,arnin1
c:\il\a.vb%#3& : warnin1 BC40004: sub 'abc' conEicts wit. sub 'abc' in t.e base class
'aaa' and so s.ould be declared 'S.adows'.


244258241.doc 241 od 272
For the sake of revision, whenever two subs are created with the same name in the base and
derived classes, the shadows keyword must be implemented. Not doing so, will result in a
pesky warning No.BC40004.

This is proved by the warning issued by the above example, where the base class aaa has a
sub abc, and the derived class bbb too has the same sub abc.

The sub pqr is also present in the two classes, but there is no error or warning issued for it,
as the sub pqr is 'private' in the base class, and thus, not visible in the derived class bbb.
The class bbb remains unaware of the sub pqr in class aaa, and hence, no warnings get
generated.

Had we changed the private access modifer to protected, a warning would have been issued,
since derived classes cannot access protected members.

Shadowing an inherited name does not result in an error, but only in a warning. This is
because, if the base class aaa does not have a sub pqr, and if one is introduced later, derived
classes like bbb that have a pqr sub should not give an error. A warning is OK.

Thus, whenever a method is added to the base class that was not present earlier, but exists
in the derived classes, no errors result. A warning is issued as the method in the base class
can either be removed by the shadows keyword or the overloads keyword, but not by both.


a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 ...
a.ab.
a.01r
End Sub
End .lass
Class aaa
8ubli. Sub ab.()
System.Console.WriteLine("aaa ab.")
End Sub
End Class
Class bbb
6n#erits aaa
8rivate S#ado4s Sub ab.()
System.Console.WriteLine("bbb ab.")
End Sub
0ubli. sub 7yz
ab.
end sub
end Class
Class ...
6n#erits bbb
Sub 01r()
ab.
My;ase.ab.
7yz
End Sub
End Class

ut!ut
244258241.doc 242 od 272
aaa abc
aaa abc
aaa abc
bbb abc

The class aaa having sub abc, is the base class for class bbb, which too introduces a sub by
the same name. The private keyword is used in the class bbb on the sub abc. Thus, the sub
abc remains hidden from any class derived from it, such as class ccc.

Now, when we call the sub abc from the object 'a' of type ccc, since the class ccc does not
have a sub abc, the system moves on to class bbb. Since it does not see any sub called abc,
as it is private, the sub abc from class aaa is called instead. Then, the sub pqr is called from
the class ccc, where the subs of abc, MyBase.abc and xyz are called.


The frst call of abc will be attended by the sub abc from class aaa, for the reasons
mentioned earlier. The second call with the identifer of MyBase, will call the sub abc from
the base class bbb. However, as it does not have the sub abc due to it being private, the sub
will be called from the class aaa, like before.

Finally, the sub xyz will be called from the class bbb. The sub xyz simply calls the sub abc
again. As access modifers are not applicable to members of the same class, the private sub
abc in the class bbb gets executed.

The things we do with the class statement!

a.vb
.lass zzz
in#erits System.9rray
s#ared Sub Main()
End sub
End .lass

$rror
c:\il\a.vb%2& : error BC300#': In.eritin1 fro) 'S+ste).Arra+' is not valid.

There are four classes that a class cannot derive from. These classes are System.Array,
System.Delegate, System.Enum and System.ValueType. There is no reason specifed for this
constraint.

a.vb
.lass zzz
in#erits zzz
s#ared Sub Main()
End sub
End .lass

$rror
c:\il\a.vb%2& : error BC302'?: Class ';;;' cannot in.erit fro) itself:

A class can inherit from other classes, but not from itself. There is a separate error message
provided for this inanity.

a.vb
8ubli. Class zzz
244258241.doc 243 od 272
S#ared Sub Main()
End Sub
End Class
inter+a.e bbb
in#erits bbb
end inter+a.e

$rror
c:\il\a.vb%'& : error BC302@': Interface 'bbb' cannot in.erit fro) itself:

Similarly, an interface is also not allowed to inherit from itself.

a.vb
.lass zzz
s#ared Sub Main()
dim a as aaa
a ne4 aaa
End Sub
End .lass
mustin#erit 0ubli. .lass aaa
end .lass

$rror
c:\il\a.vb%4& : error BC30'?@: '(ew' cannot be used on a class t.at is declared
'MustIn.erit'.
The mustinherit keyword on a class prevents creation of an instance of the class using the
'new' keyword. The class can be used as a type in the DIM statement, but it is not allowed
access by any instance members.

a.vb
.lass zzz
s#ared Sub Main()
aaa.ab.
End Sub
End .lass
mustin#erit 0ubli. .lass aaa
s#ared sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass

ut!ut
abc

The above example calls the shared sub from a mustinherit class. This does not generate
any errors, whatsoever. Thus, a mustinherit keyword, known as 'abstract' in other
languages, prevents its use directly, but allows it in derived classes.

a.vb
.lass zzz
s#ared Sub Main()
dim a as aaa
dim b as bbb
a ne4 bbb
b ne4 bbb
a.ab.
b.ab.
End Sub
244258241.doc 244 od 272
End .lass
mustin#erit 0ubli. .lass aaa
sub ab.
System.Console.WriteLine("ab.")
end sub
end .lass
0ubli. .lass bbb
in#erits aaa
end .lass

ut!ut
abc
abc

The class aaa uses the mustinherit keyword, and simultaneously creates a sub abc. The
class bbb derives from class aaa. It contains no other code. Two variables, a and b of type
class aaa and class bbb, respectively, are created in sub main. Both are instances of type
bbb.

By making both the variables as bbb objects, the sub abc present in the class aaa can be
called by both the objects. Thus, the mustinherits class must not be used directly. In
addition to this, the sub abc can be created in the class bbb, since the rules of shadowing
apply here too.

The mustinherit keyword on a class denotes the fact that the class is an incomplete type,
and should not be used directly. Thus, there are diferences in the usage of mustinherit
classes and normal classes. The major diference is illustrated in the next program.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. .lass aaa
mustoverride sub ab.
end .lass

$rror
c:\il\a.vb%'& : error BC3#4##: 'aaa' )ust be declared 'MustIn.erit' because it
contains )et.ods declared 'Mustverride'.

In a method, only the signature sufces when the mustoverride keyword is attached to it.
Thus, there is no need of an 'end sub' or any code. Howevrer, this keyword can only be used
on a class that is stamped as mustinherit. Since this clause was not implemented, the
compiler gives the above error message.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
mustin#erit 0ubli. .lass aaa
mustoverride sub ab.
0ubli. sub 01r
end sub
end .lass
244258241.doc 245 od 272
0ubli. .lass bbb
in#erits aaa
end .lass

$rror
c:\il\a.vb%#0& : error BC30?#0: Class 'bbb' )ust eit.er be declared 'MustIn.erit' or
override t.e followin1 in.erited 'Mustverride' )e)ber%s&: 8ublic Mustverride
Sub abc%&.

After inserting the keyword of mustinherit on the class aaa, the error vanishes. Also,
creating a sub pqr with code gives no error. The problem arises only when class bbb is
derived from class aaa. The compiler points out the missing implementation of the method
abc, and suggests two options for solving it.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
mustin#erit 0ubli. .lass aaa
mustoverride 0ubli. sub ab.
0ubli. sub 01r
end sub
end .lass
0ubli. .lass bbb
in#erits aaa
0ubli. overrides sub ab.
end sub
end .lass

The keyword overrides has been added to the sub abc. The absence of this keyword would
result in an error. Thus, every incomplete method in the class aaa has to be implemented in
the class bbb with the overrides keyword. The second suggestion is implemented as follows.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
mustin#erit 0ubli. .lass aaa
mustoverride 0ubli. sub ab.
mustoverride 0ubli. sub 01r
end .lass
mustin#erit 0ubli. .lass bbb
in#erits aaa
0ubli. overrides sub ab.
end sub
end .lass
0ubli. .lass ...
in#erits bbb
0ubli. overrides sub 01r
end sub
end .lass

In this approach, the class aaa uses the mustinherit keyword. It has two subs abc and pqr,
with only their prototypes. These obviously are marked with the keyword mustoverride. The
244258241.doc 24! od 272
class bbb is incomplete, and cannot be used, as it inherits from the class aaa. It only
implements the sub abc and not the sub pqr.


Therefore, the class bbb is marked as mustinherit. The class ccc is alright, as it derives from
class bbb and implements the sub pqr also. Thus, in all, there are two alternatives, i.e.
either implement all subs present in the mustinherit base class within the derived class, or
use the mustinherit keyword.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
notin#eritable 0ubli. .lass aaa
end .lass
0ubli. .lass bbb
in#erits aaa
end .lass

$rror
c:\il\a.vb%>& : error BC302@@: 'bbb' cannot in.erit fro) class 'aaa' because 'aaa' is
declared '(otIn.eritable'.

The keyword notinheritable prevents any other class from inheriting from the class. Thus, as
the class aaa is declared notinheritable, the class bbb cannot be derived from it. However,
the class functions as a normal class.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
notin#eritable mustin#erit 0ubli. .lass aaa
end .lass
0ubli. .lass bbb
in#erits aaa
end .lass

$rror
c:\il\a.vb%'& : error BC3#40>: 'MustIn.erit' and '(otIn.eritable' cannot be
co)bined.
The mustinherit keyword specifes that the class cannot be used directly, but only through
inheritance. The notinheritable is the reverse, i.e. it can only be instantiated and used for
inheritance. Thus, this causes the contradiction, and the obvious error results.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
Must6n#erit Class aaa
8ubli. MustAverride Sub ab.()
End Class
Must6n#erit Class bbb
6n#erits aaa
8ubli. S#ado4s Sub ab.()
244258241.doc 247 od 272
End Sub
End Class
Class ...
6n#erits bbb
0ubli. s#ado4s sub ab.
end sub
End Class

$rror
c:\il\a.vb%#0& : error BC3#404: '8ublic S.adows Sub abc%&' cannot s.adow a )et.od
declared 'Mustverride'.
c:\il\a.vb%#3& : error BC30?#0: Class 'ccc' )ust eit.er be declared 'MustIn.erit' or
override t.e followin1 in.erited 'Mustverride' )e)ber%s&: 8ublic Mustverride
Sub abc%&.

The class aaa in the above program is tagged with mustinherit, and has a sub abc with the
mustoverride keyword. Then, the class bbb is derived from class aaa, with a shadow on the
sub abc. This results in a grave error, since the act of shadowing hides the sub abc from the
class aaa.

If the sub abc is not implemented in the class aaa, which derives from bbb, the compiler
throws an error. This is because, any other class such as ccc, which derives from class bbb,
cannot defne the code for sub abc. This is because, the middle class bbb hides it from the
original base class aaa. This removes all the options of specifying a derived or descendant
sub in the class ccc. The shadows keyword is used only to get rid of the pesky warning.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class aaa
8ubli. overridable Sub ab.()
end sub
End Class
0ubli. .lass bbb
in#erits aaa
8ubli. notoverridable overrides Sub ab.()
end sub
end .lass
0ubli. .lass ...
in#erits bbb
8ubli. overrides Sub ab.()
end sub
end .lass

$rror
c:\il\a.vb%#?& : error BC302?=: '8ublic verrides Sub abc%&' cannot override '8ublic
verrides (otverridable Sub abc%&' because it is declared '(otverridable'.

The class aaa has a sub abc with the override modifer. Thus, it allows any derived class to
override it. Then, the class bbb derives from the class aaa, since it wants to override the sub
abc. The override modifer here is optional. In addition to this, there is a notoverridable
modifer. This does not give any errors in the class bbb.

244258241.doc 248 od 272
However, the modifer fags an error in class ccc, as we have attempted to override sub abc
here. The notoverridable modifer turns down any overrides to the sub in the base class. In
a sense, what notinheritable is for a class, notoverridable is for an individual sub.
a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class aaa
8ubli. notoverridable Sub ab.()
end sub
End Class

$rror
c:\il\a.vb%?& : error BC3#0>>: '(otverridable' cannot be s!eciBed for )et.ods t.at
do not override anot.er )et.od.

The above error comes into play because, the notoverridable keyword can be used on a
method that actually overrides another method. Thus, two conditions need to be satisfed for
employing the notoverridable keyword:
Firstly, in the base class, the method should say overridable.
Secondly, in the derived class containing the keyword notoverridable, the sub must
have the overrides keyword.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class aaa
8ubli. mustoverride notoverridable Averridable Sub ab.()
end sub
End Class

$rror
c:\il\a.vb%?& : error BC30#==: nl+ one of '(otverridable'9 'Mustverride'9 or
'verridable' can be s!eciBed.

The three modifers of notoverridable, mustoverride or overridable cannot be used at the
same time, as they are mutually exclusive.


a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class aaa
8ubli. s#ared overridable Sub ab.()
end sub
End Class

$rror
c:\il\a.vb%?& : error BC30'0#: 'S.ared' cannot be co)bined wit. 'verridable' on a
)et.od declaration.

244258241.doc 24" od 272
The shared keyword cannot be used in conjunction with the modifers Overridable,
NotOverridable, or MustOverride.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
notin#eritable Class aaa
8ubli. MustAverride Sub ab.()
End Class

$rror
c:\il\a.vb%?& : error BC30?0=: '(otIn.eritable' classes cannot .ave )e)bers
declared 'Mustverride'.

There are a number of restrictions everywhere. The NotInheritable keyword cannot be used
on classes that have methods with the keyword MustOverride, since these methods have to
be implemented in derived classes. The class aaa is tagged as notinheritable. Therefore, it
cannot be used as a derived class.

The other keywords that cannot be used with notinheritable are overridable and
notoverridable. The overridable restriction is easy to understand, since a derived class can
override it. Finally, notinheritable classes do not work with derived classes.
a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. Class aaa
8ubli. overridable overridable Sub ab.()
end sub
End Class

$rror
c:\il\a.vb%?& : error BC30#=>: S!eciBer is du!licated.

Duplicates always create a problem. The same is true for keywords and modifers. They
cannot be used twice in succession. The generic error message displayed above is shown.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
overrides sub ne4
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC302>3: 'Sub (ew' cannot be declared 'verrides'.

The constructor can never be declared as overrides, since no one can override a constructor.

a.vb
.lass zzz
s#ared Sub Main()
244258241.doc 25# od 272
End Sub
overridable sub ne4
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC303?4: 'Sub (ew' cannot be declared 'verridable'.

The same error is displayed as before, since a constructor cannot be declared as overridable.
The earlier error message is a specifc one, whereas the one displayed here is generic, as it
applies to any sub that uses an inappropriate modifer.

Till now, we have discussed the diferent modifers that can be placed on a sub or a
function. Let us now look at other aspects of a sub.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.
End Sub
0ubli. sub ab.
System.Console.WriteLine("vijay")
e7it sub
System.Console.WriteLine("vijay")
e7it sub
end sub
End .lass

ut!ut
vi*a+

The use of exit sub in a sub assists in quitting out of the sub immediately. This behavior is
similar to the return statement. All lines of code after the exit sub are ignored. However, no
warning is issued that the above lines of code are not being executed.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
0ubli. +un.tion ab.
e7it sub
end +un.tion
End .lass

$rror
c:\il\a.vb%'& : error BC300?': '$0it Sub' is not valid in a 4unction or 8ro!ert+.

The exit sub statement cannot be used in a function or a property.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
0ubli. sub ab.
ab. 10
end sub
244258241.doc 251 od 272
End .lass

$rror
c:\il\a.vb%'& : error BC300?>: $0!ression is a value and t.erefore cannot be t.e
tar1et of an assi1n)ent.

In a sub, we cannot return a value. Therefore, we cannot equate the name of the sub to a
number, like we can do in a function.

a.vb
.lass zzz
s#ared Sub Main()
End Sub
0ubli. sub ab.
return 100
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC30?4=: 'Deturn' state)ent in a Sub or a Set cannot return a
value.

In a sub, a return with a value is not permissible. The compiler catches this glitch and gives
the above error.
a.vb
.lass zzz
s#ared Sub Main()
End Sub
End .lass
0ubli. inter+a.e aaa
sub ne4
end inter+a.e

$rror
c:\il\a.vb%?& : error BC303?3: 'Sub (ew' cannot be declared in an interface.

The interface can have method prototypes, but it cannot have a sub called New, since
constructors are completely forbidden in an interface. A sub Main can exist in the interface
aaa, but no constructors are allowed.

a.vb
.lass zzz
s#ared Sub Main()
zzz.ab. 10
End Sub
s#ared 0ubli. sub ab.(i as inte$er)
end sub
End .lass

$rror
c:\il\a.vb%3& : error BC30>00: Met.od ar1u)ents )ust be enclosed in !arent.eses.

A sub or a function with parameters must enclose the parameters passed to it within round
brackets. Simply specifying the parameters without the brackets, as shown above, is
unacceptable.

a.vb
244258241.doc 252 od 272
o0tion stri.t on
.lass zzz
s#ared Sub Main()
End Sub
0ubli. sub ab.(i )
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC3020@: !tion Strict n re<uires all variable declarations to
.ave an 'As' clause.

a.vb
o0tion stri.t on
.lass zzz
s#ared Sub Main()
End Sub
+un.tion ab.
end +un.tion
End .lass

$rror
c:\il\a.vb%'& : error BC302#0: !tion Strict n re<uires all function and !ro!ert+
declarations to .ave an 'As' clause.

The above two programs illustrate the concept of the option strict statement. So far, while
creating a variable or specifying a function return value, the 'as' modifer had been
implemented. This is optional, as the option strict statement is of, by default.

The option strict, when turned on, frmly demands that all variables have to be declared at
the time of creation. In a way, it is better to have this option on. This option also deals with
type conversions, which we shall cater to, on a diferent day.

o0tion e70li.it vijay

$rror
c:\il\a.vb%#& : error BC30?40: '!tion $0!licit' can be followed onl+ b+ 'n' or 'F'.

The option strict can only be followed by either of the words 'on' or 'of'. Incorporating any
words, other than the ones allowed, generates the above error message.
a.vb
.lass zzz
o0tion stri.t vijay
s#ared Sub Main()
End Sub
End .lass

$rror
c:\il\a.vb%2& : error BC30?2=: '!tion' state)ents )ust !recede an+ declarations or
'I)!orts' state)ents.

The option statements must be the frst statement, and should precede all the other
statements, excluding comments. It must be the frst non-comment statement, and must
precede 'using' and the namespace defnitions. Thus, it must be placed at the very
beginning.

244258241.doc 253 od 272
o0tion stri.t on
o0tion stri.t o++

$rror
c:\il\a.vb%2& : error BC3022': '!tion Strict' state)ent can onl+ a!!ear once !er
Ble.

One last condition for the option statement is that, there can be only one such statement,
since even a single such statement proves to be quite a handful for the compiler.
#0. 8ara)eters to 8rocedures

All the code of Visual Basic applications is written in procedures. There are four diferent
types of procedures in Visual Basic:
The frst is a sub, which does not return a value.
The second is a Function that returns a value.
The third is the event handling code.
The fourth is a property module that also contains code.

In VB, code cannot be written anywhere but in the above four procedures. The advantage of
using procedures is that they make applications more readable, since code that is oft
repeated, is positioned within them. It would not be wrong to say that without procedures,
no application can be written in VB.

The main logic behind having procedures is to write the code once, and then, call it several
times from diferent places. By writing procedures, the program can be broken down into
smaller logical units. It is always easier to debug 10 small procedures, rather than
debugging one large program.

It is on account of the presence of procedures that the functions like WriteLine are available,
and which can be used without us having to worry about how they are written.
The sub access modifer is 'public' by default, and thus, a sub can be called from anywhere
in the program.

a.vb
.lass zzz
s#ared Sub Main()
End Main
End .lass

$rror
c:\il\a.vb%3& : error BC30?=>: '$nd' state)ent not valid.

The sub Main requires an 'end sub', or else the above stated error is generated. In the world
of VB, there is no 'begin' statement, but there is a mandatory 'end' statement.

a.vb
.lass zzz
s#ared Sub Main()
.all ab.
End sub
s#ared sub ab.
System.Console.WriteLine("#i")
end sub
244258241.doc 254 od 272
End .lass

ut!ut
.i

To call a sub or a function, the 'call' statement may be used. This, however is optional, and
hence, is not implemented in right earnest. But you are bound to encounter it sometime.

Passing Parameters

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( i % j as inte$er)
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC30'2@: All !ara)eters )ust be e0!licitl+ t+!ed if an+ are.

Since the option of 'strict' is switched of, we are not required to specify the data types of the
parameters. They default to type Object.

The erratic and fastidious behavior witnessed above, is the fallout of having specifed the
type for only one parameter, and not for all of them. You should either specify the types for
all the parameters or for none of them. Any half-baked action results in an error being
hurled at us.

a.vb
.lass zzz
s#ared Sub Main()
End sub
+un.tion ab.( ab. as inte$er)
end +un.tion
End .lass

$rror
c:\il\a.vb%4& : error BC30'30: 8ara)eter cannot .ave t.e sa)e na)e as its
deBnin1 function.

There are subtle diferences between functions and subs. In a sub, the parameters can have
any name, but this is not true of a function. You may recall that in a function, there are two
ways of returning values; The frst is by using the return statement, and the second is by
simply initializing the name of the function.

If a parameter is assigned the same name as a function, the compiler is sure to feel bafed.
This is because, it is an extremely arduous task to ascertain whether the programmer is
setting the return value, or is changing the value of the parameter. This error applies to
functions only, since subs do not return values.

a.vb
.lass zzz
s#ared Sub Main()
dim j as inte$er 100
244258241.doc 255 od 272
dim a as ne4 zzz
a.ab.(j)
System.Console.WriteLine(j)
j 100
a.ab.((j))
System.Console.WriteLine(j)
End sub
sub ab.( byre+ i as inte$er)
i 10
end sub
End .lass

ut!ut
#0
#00

When parameters are passed by reference, the changes made in the sub are also refected in
the original variable. Therefore, the frst call to sub abc changes the value of j from 100 to
10. So far, so good!

After resetting the value of j back to 100, the sub abc is called again, but this time, j is
enclosed within a pair of round brackets. The brackets are a subtle way of informing the
compiler that the parameter is being passed by value and not by reference. Thus, the second
call, which is a call by value, does not lead to a change in the value of the variable j. Even if
the parameter i is set to byval, the use of round brackets shall not cause any error.

When it comes to passing parameters, there are four distinct possibilities to mull over. The
parameters can either be 'byval' or 'byref' types, or they may be 'value' or 'reference' types.

It is easiest to understand the concept of passing parameters by value. Here, any change in
the value of the variable in the procedure, is not refected in the original variable.
Passing parameters by reference is very distinct from the above. The value contained in the
original variable, changes with any change introduced in the variable in the sub. Reference
type variables are actually pointers to the original data.

A 'pass by value' afects only the value of the variable or the member, without afecting the
original variable; whereas, a 'pass by ref' changes both, the object, i.e. the original variable it
is pointing to, as well as, its members.

The advantage of 'pass by ref' is that the calling sub can change the value of the parameters.
There is no signifcant overhead in passing a variable either by ref or by value. However, it is
advantageous to pass larger value types such as structures by ref, and not by value, or else,
a large number of variables will have to be copied on to the stack.

Optional Arguments

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.(100%!00)
a.ab.(100%10)
a.ab.(,0)
End sub
sub ab.( i as inte$er % o0tional j as inte$er 10)
244258241.doc 25! od 272
System.Console.WriteLine("&0' &1'"% i % j)
end sub
End .lass

ut!ut
#00 200
#00 #0
'0 #0

At times, there exist a large number of parameters to a procedure. This is where the concept
of optional parameters comes handy.

The sub abc has two parameters, i and j. The parameter j is assigned a value of 10. It is
optional, since it is tagged with the 'optional' keyword.

However, the sub abc can be called with two parameters, 100 and 200, as a result of which,
the 'optional' keyword is devoid of any efect at all. The default value is overwritten with the
new value of 100. Hence, the output shows the value of j as 200.

The second call to the sub abc results in assigning the default value of 10 to the second
parameter. However, there is no technique for notifying the sub abc about whether the call
has been made with two parameters or with a single one. So, it behaves like it did earlier,
and reassigns the value of 10 to the second parameter.

The last call to sub abc is made with one parameter only. Therefore, the frst parameter i
assumes this new value of 50, thus, resulting in the second parameter j assuming its
default value of 10.

The 'optional' keyword proves to be useful, since the user is not required to call the
procedure with all its parameters. The parameters that have been overlooked are assigned
their default values. However, the sub has no way of identifying the parameters that it has
been called with. Now, replace the above sub statement with the following:

sub ab.( i as inte$er % o0tional j as inte$er )

$rror
c:\il\a.vb%>& : error BC30>#2: !tional !ara)eters )ust s!ecif+ a default value.

The optional parameter must have a default value, or else, the very essence of the optional
keyword is lost. This is the only way of assigning a value to the optional parameter.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( i as inte$er 10)
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC32024: 6efault values cannot be su!!lied for !ara)eters
t.at are not declared '!tional'.

244258241.doc 257 od 272
The reverse is also true. A parameter cannot be assigned a default value, unless it is
prefxed with the 'optional' keyword.

a.vb
.lass zzz
dim 5 as inte$er 10
s#ared Sub Main()
End sub
sub ab.( i as inte$er % o0tional j as inte$er 5 )
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC300'@: Constant e0!ression is re<uired.

The second condition imposed on optional arguments is that, the value has to be a constant
expression, which can be determined at compile time. Thus, the instance variable k, which
has a value of 10, is not declared as a constant, since its value can be changed before
invoking the sub abc. Thus, an error is thrown.

a.vb
.lass zzz
dim 5 as inte$er 10
s#ared Sub Main()
End sub
sub ab.( i as inte$er % o0tional j as inte$er i )
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC304'#: (a)e 'i' is not declared.

Furthermore, other parameters cannot be used to supply a value to the default parameter.
The other parameters are not visible to each other, as has been pointed out by the error
message.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( o0tional i as inte$er 10% j as inte$er )
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC30202: '!tional' e0!ected.

The last rule is that, if we make any one parameter optional, all the parameters following it
have to be made optional. Therefore, since the frst parameter i has been made optional, the
parameter j, which follows i, must also be made optional.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.(100%%1000)
244258241.doc 258 od 272
End sub
sub ab.( i as inte$er % o0tional j as inte$er 10 % o0tional 5 as inte$er (0)
System.Console.WriteLine("&0' &1' &!'"%i%j%5)
end sub
End .lass

ut!ut
#00 #0 #000

In the above example, the second and the third parameters are declared as optional. While
calling the abc sub, we intend to skip the second parameter, but we would like to specify the
third parameter. This is obtained by not specifying any value between the commas, as
revealed above. Use of optional parameters is another way of overloading variables, where
the data type is the same.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
End sub
sub ab.( i as inte$er % o0tional j as inte$er 10 )
end sub
sub ab.( i as inte$er )
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC30300: '8ublic Sub abc%i As Inte1er9 L* As Inte1er I #0M&' and
'8ublic Sub abc%i As Inte1er&' cannot overload eac. ot.er because t.e+ diFer onl+
b+ o!tional !ara)eters.

The above error emanates from the fact that the two abc subs that have been overloaded,
difer only in the second sub, which has an optional parameter. We had mentioned earlier
that procedures can share the same name, but must have diferent parameters. They would
be deemed to be distinct, since the method signatures would vary.

In the above case, we can have both the subs abc, with the same single integer as a
parameter. However, the compiler would be thoroughly bewildered as to which abc to call.
Therefore, it would report an error.

The frst sub abc can be called with either one, or two parameters, while the second sub abc
is to be called only with one parameter. But, when the sub abc is called with one single
parameter, the compiler is awe-struck, as both the subs ft the bill. Observe that the default
values in the error message are placed within square brackets.



a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
End sub
sub ab.( i as inte$er % o0tional j as inte$er 10 )
end sub
sub ab.( i as inte$er % o0tional j as strin$ "#i")
end sub
244258241.doc 25" od 272
End .lass

$rror
c:\il\a.vb%'& : error BC30?@?: '8ublic Sub abc%i As Inte1er9 L* As Inte1er I #0M&' and
'8ublic Sub abc%i As Inte1er9 L* As Strin1 I 2.i2M&' cannot overload eac. ot.er
because t.e+ diFer onl+ b+ t.e t+!es of o!tional !ara)eters.

The error appears much the same as the one shown above. Both the abc subs have the frst
parameter as an integer, but the second one is optional. The types of the second parameter
are diferent. The ambiguity arises when the sub abc is called with a single parameter, since
the VB compiler realizes that both the abc subs can be executed under such a situation.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
End sub
End .lass
.lass yyy
overridable sub ab.( i as inte$er % o0tional j as strin$ "#i")
end sub
end .lass
.lass 777
in#erits yyy
overrides sub ab.( i as inte$er % o0tional j as strin$ "bye")
end sub
end .lass

$rror
c:\il\a.vb%#2& : error BC3030=: '8ublic verrides Sub abc%i As Inte1er9 L* As Strin1 I
2b+e2M&' cannot override '8ublic verridable Sub abc%i As Inte1er9 L* As Strin1 I
2.i2M&' because t.e+ diFer b+ t.e default values of o!tional !ara)eters.

The error is generated because the sub in the base class has an optional value of "hi", while
the sub in the derived class has an optional value of "bye".

Overriding a method in the base class calls for the derived class to be identical in all
respects, including the default values. The same concept applies to overriding and
overloading also. Hence, we will not reiterate them here.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
End sub
End .lass
.lass yyy
overridable sub ab.( byval i as inte$er)
end sub
end .lass
.lass 777
in#erits yyy
overrides sub ab.( byre+ i as inte$er)
end sub
end .lass

$rror
244258241.doc 2!# od 272
c:\il\a.vb%#2& : error BC303@>: '8ublic verrides Sub abc%B+Def i As Inte1er&' cannot
override '8ublic verridable Sub abc%i As Inte1er&' because t.e+ diFer b+ a
!ara)eter t.at is )ar:ed as 'B+Def' versus 'B+5al'.

While we are converging around the subject of overloading methods, it would be pertinent to
mention that the above error creeps in, since the two subs abc have the parameter i
specifed as byval in the base class, and as byref in the derived class. They must be either
byval or byref in both, the base class, as well as the derived class.

a.vb
.lass zzz
s#ared Sub Main()
End sub
End .lass
.lass yyy
sub ab.( i as inte$er % o0tional j as aaa 1!)
end sub
end .lass
stru.ture aaa
dim i 5 as inte$er
end stru.ture

$rror
c:\il\a.vb%?& : error BC3#40': !tional !ara)eters cannot .ave structure t+!es.

The optional parameters cannot have a type of a structure specifed for them. Since the
optional parameter in the sub is specifed to be of type structure aaa, the error is reported.

So far, we have been passing parameters by position. This is because, we have been passing
them in the same sequence as they had been defned in the sub or function. Now, we shall
pass them by name instead.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.(1%"#i"%5C!)
a.ab.(!0%jC"no"%5C10)
a.ab.(iC!00%jC"no"%5C!0)
End sub
sub ab.( i % j % 5 )
System.Console.WriteLine("&0' &1' &!'"%i%j%5)
end sub
End .lass

ut!ut
# .i 2
20 no #0
200 no 20

The sub abc takes three parameters, i, j and k. We can pass them either by position, i.e. by
specifying the parameters as we have been doing so far, or by employing the 'pass by name'
method. In this method, we use the name of the parameter, followed by the := sign, and
then, followed by the actual value. The sub that is called has no means of identifying the
method that has been used.

244258241.doc 2!1 od 272
a.ab.(!00 % 5 C !0 % "no")

c:\il\a.vb%?& : error BC3024#: (a)ed ar1u)ent e0!ected.

We do not have 'carte blanche', i.e. complete discretion, to act in any manner that we desire.
The basic rule in VB is that, once we initiate the process of passing parameters using the
concept of 'call by name', we cannot switch to 'call by position' midway. We have to stick to
the same method till the end of the program.

The single biggest beneft of 'call by name' comes to the fore, when a method has a vast
number of optional parameters. 'Call by name' is easier to implement, since there is no need
to place inessential commas between blank parameters. Whether we are passing parameters
by value or by name, the requisite parameters have to be specifed.

a.vb
.lass zzz
s#ared Sub Main()
End sub
s#ared sub ne4( i as inte$er)
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC304=@: S.ared 'Sub (ew' cannot .ave an+ !ara)eters.

While we are on the subject of parameters, we wish to enlighten you about the fact that the
static constructor cannot have any parameters. This is because, the static constructor is
called at the time of loading the object, and at this stage, no control can be exercised over it.

a.vb
.lass zzz
s#ared Sub Main()
End sub
8ubli. 8ro0erty aa() 9s 6nte$er
Jet
End Jet
Set (byre+ i 9s 6nte$er)
End Set
End 8ro0erty
End .lass

$rror
c:\il\a.vb%=& : error BC3#0?': 'Set' !ara)eter cannot be declared 'B+Def'.

A property parameter in the set cannot have a byref, since it is not allowed to change the
value of the original variable. The Set accessor is called, whenever the value of the property
has to be changed. It is not used to change the value of the variable that sets the value of
the property.

a.vb
.lass zzz
s#ared Sub Main()
End sub
8ubli. de+ault 8ro0erty aa() 9s 6nte$er
Jet
End Jet
244258241.doc 2!2 od 272
Set (i as inte$er)
End Set
End 8ro0erty
End .lass

$rror
c:\il\a.vb%4& : error BC3#04>: 8ro!erties wit. no re<uired !ara)eters cannot be
declared '6efault'.

A default property or an indexer requires a parameter, since that is the only available means
of using it as an index into an array of values.

a.vb
im0orts system
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.("Hi"%10%!0%(0)
a.ab.(";ye")
2im b() 9s inte$er &100%!00'
a.ab.("3o"% b)
End sub
sub ab.( 5 as strin$% 0aramarray s() as inte$er)
dim i%j as inte$er
j s.JetN00er;ound(0)
System.Console.WriteLine("&0' &1'" % 5 % j)
/or i 0 -o s.JetN00er;ound(0)
System.Console.Write(s(i) & " ")
3e7t i
System.Console.WriteLine()
end sub
End .lass

ut!ut
"i 2
#0 20 30
B+e 3#
(o #
#00 200

The program has a procedure that acts like a WriteLine function, where a multiple number
of parameters can be specifed. Normally, the hawk-eyed VB compiler ensures that the
number of parameters allotted to the procedure, does not exceed its limit. The only way of
ascertaining this is by using a parameter array.

The sub abc takes two parameters, i.e. a string and a paramarray of type integer. The
paramarray keyword stands for an 'array of parameters', which can take a varying number
of arguments. The frst call to the sub abc takes one string and three individual integers.
The string value is assigned to the string parameter, and the three integers are stored in 's',
which is a paramarray type. Thus, 's' now becomes an array of three integers.

The array type has a function called GetUpperBound, which returns the largest dimension
or upper bound of the size of the array. The parameter 0 is a dimension parameter. Since the
array comprises of 3 members, the function returns 2, which is 1 less than the size.

244258241.doc 2!3 od 272
We display the return value of this function, and then, use the 'for next' loop to faunt the
individual members. Had the GetUpperBound function returned the actual size of the array,
we would then have had to subtract 1 from the value contained in variable j. This loop
prints out the individual members of the array. The sub abc is then called with only one
parameter. The value of -1 returned by the GetUpperBound function signifes that the value
is nothing or null.

In the third case, we create an array 'b' of two integers, and pass only this array as a
parameter. The sub abc is oblivious to whether we are passing an array or individual values.
However, the end result is that we obtain an array containing all the integers.

This is the manner in which we can handle a varying number of arguments. Let us consider
the restrictions that are imposed upon parameter arrays.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( 5 as strin$% 0aramarray s() as inte$er % 0aramarray t() as strin$)
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC30#@2: 8ara)Arra+ !ara)eter )ust be last in !ara)eter list.

We can have only one paramarray per method. The above error has come about, since there
exist two paramarrays of diferent types, which is not permissible.

The second condition is that the paramarray has to be the last parameter in the sequence.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( 5 as strin$% byre+ 0aramarray s() as inte$er )
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC30??=: 8ara)Arra+ !ara)eters )ust be declared 'B+5al'.

The third restriction is that the paramarray has to be passed as byval, and not as byref. This
is very obvious, since if both were allowed, the system would have had to fgure out which of
the original variables can be modifed. The documentation recommends the use of the byval
keyword, even though it is the default value. The sub with the paramarray parameter
receives a one-dimensional array. The default is an empty array of the paramarray data type.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( o0tional 5 as strin$ "#i"% 0aramarray s() as inte$er )
end sub
End .lass

244258241.doc 2!4 od 272
$rror
c:\il\a.vb%4& : error BC3004?: Met.od cannot .ave bot. a 8ara)Arra+ and !tional
!ara)eters.

Life is full of 'either-or' choices. If we use the 'optional' keyword, the 'paramarray' keyword
cannot be specifed. Thus, we can have either 'optional' or 'paramarray' parameters.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.(sC10)
End sub
sub ab.(0aramarray s() as inte$er )
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC30'>=: (a)ed ar1u)ent cannot )atc. a 8ara)Arra+
!ara)eter.

There is no way by which a named argument can be used to specify a paramarray
parameter. This is because, the paramarray parameters are varying in number, and they
have to be separated by spaces. This surely would confound the compiler. Hence, only
parameters by position can be used.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.(0aramarray s as inte$er )
end sub
End .lass

ut!ut
c:\il\a.vb%4& : error BC300'0: 8ara)Arra+ !ara)eter )ust be an arra+.

The paramarray parameter must be declared as an array, since its job is to store the
multiple values that can be theoretically passed.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.(0aramarray s(%) as inte$er )
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC300'#: 8ara)Arra+ !ara)eter )ust be a one3di)ensional
arra+.

The second condition is that the paramarray can only be a one-dimensional array.

244258241.doc 2!5 od 272
An overloaded procedure must satisfy certain criteria, i.e. the overloaded procedures must
have the same name, or else, overloading makes no sense. Since the names are identical,
the overloaded procedures must difer from each other in three diferent ways:
The frst is that the procedures must have diferent number of arguments.
The second is in respect of the order of the arguments.
The third is relates to the data types of the arguments.

The three aforementioned aspects put together, are collectively called the 'signature' of the
procedure.

The modifers of 'pubic', 'shared' and 'static' do not form a part of the procedure signature.
The other entities that do not belong to the method signature are argument names,
keywords like 'byref' and 'optional', and the return data types of the functions.

a.vb
.lass zzz
s#ared Sub Main()
End sub
End .lass
.lass aaa
overloads +un.tion ab.() as inte$er
end +un.tion
overloads +un.tion ab.() as strin$
end +un.tion
end .lass

$rror
c:\il\a.vb%?& : error BC3030#: '8ublic verloads 4unction abc%& As Inte1er' and
'8ublic verloads 4unction abc%& As Strin1' cannot overload eac. ot.er because
t.e+ diFer onl+ b+ return t+!es.

The above error crops up, since the two abc functions encompass the same parameter lists,
but they return an integer in one case, while a string in the other. The return value of a
function is not mission-critical, since the value need not be stored.

Therefore, functions with diferent return values cannot be overloaded. However, functions
that overload each other with diferent argument lists may have diferent return values.

a.vb
.lass zzz
s#ared Sub Main()
End sub
End .lass
.lass aaa
overloads sub ab.()
end sub
overloads +un.tion ab.() as strin$
end +un.tion
end .lass



$rror
c:\il\a.vb%?& : error BC3#0=3: 'abc' conEicts wit. a function b+ t.e sa)e na)e
declared in 'aaa'.

244258241.doc 2!! od 272
The aforementioned error is tossed at us because the sub abc does not take any parameters,
and simultaneously, the function abc that ensues, is also devoid of any parameters. Thus,
the compiler is unable to discriminate between the sub and the function, since they both
have the same signature.

By assigning the function and the sub with diferent parameter lists, the error ebbs of.
Internally, VB does not distinguish between subs and functions. If a function and a property
both have the same name, the above error is reported.

For the sake of revision, we repeat that whenever a function like abc( i as integer, optional j
as string = "hi") is created, in efect, we are creating two functions: one with a single integer
and the other with an integer and a string. Therefore, another function with the above
signature cannot be created. These rules get more complicated when multiple argument lists
are involved.

a.vb
.lass zzz
s#ared Sub Main()
dim a as ne4 zzz
a.ab.(10)
a.ab.(10%!0)
a.ab.(10%!0%(0)
End sub
overloads sub ab.(0aramarray i() as inte$er)
System.Console.WriteLine("0aramarray")
end sub
overloads sub ab.(i as inte$er )
System.Console.WriteLine("sin$le")
end sub
End .lass

ut!ut
sin1le
!ara)arra+
!ara)arra+

The above example demonstrates the complexities associated with the paramarray during
'procedure overloading'. There are two subs called abc. However, since the signatures for all
of them are diferent, no compiler errors are generated.

The signatures are diferent because, the frst sub takes a paramarray, while the second one
takes a single integer. When the sub abc is called with a single integer, there is bound to be
a dilemma as to which of the subs is to be called, since they both ft the bill.

In the frst call, the system prefers the single sub with an integer as parameter. For the
second and the third calls of the sub abc, the system calls the sub with the single
paramarray, since the sub with the single parameter does not ft the bill.

We have tried to introduce one more defnition in

overloads sub ab.(i as inte$er % 0aramarray j() as inte$er)
System.Console.WriteLine("t4o")
end sub

244258241.doc 2!7 od 272
We had hoped that it would correspond with all the three calls. However, we land up with
errors galore, as the compiler gets utterly bafed!

A sub with a paramarray parameter represents at least three subs. The frst is a sub that
has a single dimensional array, the second is a sub with no parameter, and a third is a sub
that has a series of individual parameters, of the data type of paramarray.

Before concluding this treatise on procedures, let us examine a few error messages that we
have not touched upon so far.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.()
e7it 0ro0erty
end sub
End .lass

$rror
c:\il\a.vb%'& : error BC300??: '$0it 8ro!ert+' is not valid in a 4unction or Sub.

Unlike a return statement, an Exit property statement cannot be used to quit out of a
property. In the same way, we cannot replace the word 'property' with 'function'. It will cast
an error, as depicted below:

C:\il\a.vb%'& : error BC300?=: '$0it 4unction' is not valid in a Sub or 8ro!ert+.

a.vb
.lass zzz
s#ared Sub Main()
End sub
+un.tion 3e4
end +un.tion
End .lass

$rror
c:\il\a.vb%4& : error BC304@3: Constructor )ust be declared as a Sub9 not as a
4unction.

The constructor must be declared as a sub and not as a function, since constructors do not
return values. By defning them as functions, we are explicitly stating that they do return
values.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub 3e4 #andles e.ab.
end sub
End .lass
$rror
c:\il\a.vb%4& : error BC304@=: 'Sub (ew' cannot .andle events.

244258241.doc 2!8 od 272
The constructor cannot handle any events, since it can never be called explicitly. Thus,
using the 'handles' keyword with it generates a compiler error. A constructor's singular task
is to get called only at the time of creation of an object. Thus, it cannot handle events.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ne4 im0lements yyy.ab.
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC3#042: 'Sub (ew' cannot i)!le)ent interface )e)bers.

The constructor is also unable to implement any interface functions.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
sub ne4
me.ne4
end sub
End Class

$rror
c:\il\a.vb%4& : error BC302@=: Constructor '8ublic Sub (ew%&' cannot call itself:

A method is capable of calling itself. This is a well-known concept called 'recursion'. A
considerable number of computer problems are resolved by using recursion. However, a
constructor cannot call itself. If it does so, the above error is hurled at us.

a.vb
.lass zzz
s#ared Sub Main()
End sub
End .lass
.lass aaa
sub ne4
end sub
sub ne4 (0aramarray a() as inte$er)
end sub
end .lass
.lass bbb
in#erits aaa
end .lass

$rror
c:\il\a.vb%##& : error BC3203?: Class 'bbb' )ust declare a 'Sub (ew' because its
base class 'aaa' .as )ore t.an one accessible 'Sub (ew' t.at can be called wit. no
ar1u)ents.

The class aaa has two constructors, one without any parameters, and the other with a
paramarray, which also expects no parameters. The class bbb is derived from the class aaa.
This gives out the above error, as there are two 'new' subs in the base class, and they both
244258241.doc 2!" od 272
cannot be called with parameters. To dodge this error, simply add a sub new to the class
bbb, as follows:

.lass bbb
in#erits aaa
sub ne4
end sub
end .lass

$rror
c:\il\a.vb%#3& : error BC3203>: 4irst state)ent of t.is 'Sub (ew' )ust be a call to
'M+Base.(ew' or 'M+Class.(ew' because base class 'aaa' of 'bbb' .as )ore t.an
one accessible 'Sub (ew' t.at can be called wit. no ar1u)ents.


This gives rise to a diferent error, since the addition of a sub in class bbb does not resolve
the earlier error of identifying the sub 'new' as being called from the base class.

sub ne4
mybase.ne4
end sub

However, by adding a call to the base class constructor, the error retires from sight.

a.vb
.lass zzz
s#ared Sub Main()
End sub
End .lass
.lass yyy
s#ared Sub Main()
End sub
End .lass

$rror
vbc : error BC30=3>: 'Sub Main' is declared )ore t.an once in 'a': ;;;.Main%&9
+++.Main%&

There cannot be more than one occurrence of the main sub in the program. The above error
substantiates this fact. Neither of the two classes zzz or yyy can contain a main sub in
them. It is because, the system would not know as to which sub main to call, while
executing the program.

a.vb
8ubli. Class zzz
S#ared Sub Main()
End Sub
+un.tion vijay()
dim vijay as inte$er
End +un.tion
End Class

$rror
c:\il\a.vb%'& : error BC302@0: -ocal variable cannot .ave t.e sa)e na)e as t.e
function containin1 it.

244258241.doc 27# od 272
A variable and a function cannot have the same name, since it would create an imbroglio
when the variable has to be initialized. A similar error message occurs when a function and
a parameter share the same name. This has already been explained earlier in the chapter.

There are certain error messages that never get generated. One of them is 'Identifer is too
long, since the largest size of an identifer is 16384 characters'. We obviously do not have the
time to create a variable as sizeable as this.

Another error that cannot be displayed is, "Maximum number of errors has been exceeded".
This is because, the compiler will stop only when it encounters a total of 100 errors!

a.vb
.lass zzz
s#ared Sub Main()
" =,
End sub
End .lass

$rror
c:\il\a.vb%3& : error BC3003': S+nta0 error.

It is but natural to feel peeved at the petulant conduct of some people, and hence, there is a
desperate urge to let the steam of. The same is true of the compiler. When it bumps into an
error that does not fall into a predefned category, it reports it as a Syntax error.

a.vb
8ubli. Class zzz
dim a as 0rivate inte$er
S#ared Sub Main()
End Sub
End Class

$rror
c:\il\a.vb%2& : error BC30#>0: Ne+word does not na)e a t+!e.

Every statement has its own set of rules. For instance, the Dim statement expects a type
following the 'as' keyword. Since 'private' is not a type but a keyword, the above error
message is generated.

a.vb
8ubli. Class zzz
S#ared Sub 0rivate Main()
End Sub
End Class

$rror
c:\il\a.vb%2& : error BC30#>3: Ne+word is not valid as an identiBer.

In the same vein, the sub requires the name of the sub or an identifer, whereas, it has
actually been furnished with the 'private' keyword. An identifer cannot be a keyword.

a.vb
8ubli. Class zzz
a as inte$er
S#ared Sub Main()
244258241.doc 271 od 272
End Sub
End Class

$rror
c:\il\a.vb%3& : error BC30#>>: 6eclaration e0!ected.

The VB program comprises of both, declarative and the nondeclarative statements. A
nondeclarative statement, such as an assignment or a loop, cannot occur outside a
procedure. Thus, whenever there is some gibberish present outside a procedure, the above
error is thrown. A similar error message is received when a variable is created without using
the Dim statement.



a.vb
+or i 1 to 10
8ubli. Class zzz
S#ared Sub Main()
End Sub
End Class

$rror
c:\il\a.vb%#& : error BC30?>@: State)ent cannot a!!ear outside of a )et.od bod+.

Similarly, the 'for' statement cannot be used outside a method. The error, even with a slight
diference, applies to all executable statements, and are permissible only within methods.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim a as ne4 zzz
a.ab.(10 C !0)
End Sub
sub ab. ( i as inte$er)
end sub
End Class

$rror
c:\il\a.vb%4& : error BC30#@>: '&' e0!ected.

The parameters to a sub or a function, must be separated by commas. If we use colons
instead, the above error is generated. Despite removing the colon, another error gets
generated, which is as follows:

$rror
c:\il\a.vb%4& : error BC320#=: Co))a9 '&'9 or a valid e0!ression continuation
e0!ected.

a.vb
8ubli. Class zzz
S#ared Sub Main()
dim b(!) as inte$er &1 !'
End Sub
End Class

$rror
244258241.doc 272 od 272
c:\il\a.vb%3& : error BC303=0: 'O' e0!ected.

Bypassing the comma for the array would lead to yet another error, which states that the }
sign is expected. Also, the compiler casts another error, which states that an array cannot
be created and initialized at the same time, with its dimension specifed.

a.vb
.lass zzz
s#ared Sub Main()
End sub
sub ab.( s as inte$er% s as inte$er)
end sub
End .lass

$rror
c:\il\a.vb%4& : error BC3023=: 8ara)eter alread+ declared wit. na)e 's'.

There are some errors that are present for the sake of completeness, like the one just
discussed, where the two parameters have been assigned the same name.

Вам также может понравиться