Académique Documents
Professionnel Documents
Culture Documents
Vijay Mukhi (vmukhi@vsnl.com) is one of the pioneers of the Indian Infotech Industry. For
years, he has been the first to teach the emerging technologies in India thus ensuring that India
always has people trained in technologies that the world requires. Vijay has written over 80
books on computers and programming over the last eight years on subjects ranging from C, C++
(The Odyssey Series) to Animation and Networking to ERP. His newly released book ‘Java-
Servlets-JSP’ has covered many aspects of Java in the most simplified form. Vijay abhors
complexities and hence his books showcase the most difficult concepts explained through small
programs, thereby giving a good understanding. Microsoft's .Net technologies is what Vijay is
now focussing on and he aims at writing volumes on it.
Introduction
Welcome to the first installment on a series of 12 volumes dedicated to the latest technology to
hit the third rock from the sun. But before diving in and getting both feet wet, a wee bit of
background.
Microsoft has always had a habit of doing things in style. Whether it was the basic yet robust
Disk Operating System (DOS) or the (user-friendly?) Windows Operating System, Microsoft has
always managed to rewrite the rules in the computer world. In fact it won't be exaggeration to
say that today it is thanks to the efforts of Microsoft and the vision of its founder, Bill Gates, that
it is software and not machines, that occupy centrestage. But then that is another story altogether.
Notwithstanding its hegemony over operating systems, it must be said that Microsoft took its
time to wake up to the call of the Internet. Netscape was way ahead in the race, and Internet
Explorer was a distant follower, almost nowhere in the reckoning. Even as users had begun to
write off Microsoft as a non-starter for the web, it has gone and done what he does best ---
pounced back with technology that is more cutting edge than its peers.
Although, Netscape isn't history as yet, most people would rather use a browser that works better
with the latest versions of Windows. Internet Explorer literally chooses itself. Then of course
there are other utility tools like Excel, Word and Power Point - all Microsoft-owned and near-
indispensable.
And now Microsoft has come out with Microsoft.Net, a project until recently called Microsoft's
Next Generation Windows Services architecture. The objective is the integration of the Internet -
to offer software - like Word and Excel - through your browser on the computer as well as on a
range of devices such as the mobile phone and the personal digital assistant (Palm Pilot etc).
The grand design, as it were, is to change the very nature of the way people work presently.
Today we generally use one computer per person. Soon, all we shall be using would be only the
Internet. For all our needs. In other words, whenever you switch your computer on, you would be
connected directly to the Internet and not your hard disk for even the most rudimentary of tasks.
The task is enormous: every package now on offer will need additional code (even recoding). In
the new regime, Microsoft has got Visual Studio .Net which can enable even the most uninitiated
to design complex websites provided of course one is web and design savvy.
And all of this will be made possible through a new programming language called C#
(pronounced C-Sharp).
Why C-Sharp?
When people talk of computer programming languages, there is always a debate on which one is
better. C++, Java, Perl, PHP3… the arguments and counter-points can be endless. However, it is
our considered belief that that C# would be in a sense better than the rest. And there is a reason
for this.
Normally, whenever a new product is introduced, it betters the technologies of its ilk. For
existing technologies evolve with their own pros and cons. Therefore, in 1995, when Sun
introduced Java, it took the best from amongst all languages and added current technology. Now
Microsoft has done the same. Its taken the best features from C++ and Java and morphed them
into this new programming language called C#.
Imagine those who worked on Java when it was launched six years ago. Today a CV boasting of
a six-year experience in Java means the maximum possible. Simple arithmetic - Java was
launched only in '95. Similarly, if you get into C# today, only a Microsoft engineer could have
more working knowledge of it! Therefore, we don't think we need to elaborate further on the
weight that a CV with C# exposure would command! Think for yourself. You may know of
people who have struck lucky in getting a job. But when it comes to keeping it, Lady Luck is
powerless.
Indeed, technology is ruthless, in that, it breaks across all age and seniority barriers. That's the
reason why even a teenager could have as much experience with a new technology as a 40-year-
old. Unfair, but true.
Many a times, on a clear night when we look up at the stars, we can't help but wonder whether
there is intelligent life out there - or are they just like us?
For we don't believe that intellect is a quality that we are born with. In fact we are going to share
a secret with you. It is the secret of success given to us by an old gypsy woman. This magic
mantra has worked with many and we assume you would also use it in your life. In fact this is
the only assumption we make in this book.
The secret is in persistence - nothing in the world can take place of persistence. Talent will not,
nothing is more common than unsuccessful people with talent. Genius will not, unrewarded
genius is almost a proverb. Education will not, the world is full of educated derelicts. Persistence
and determination alone are omnipotent. We hope you agree with the old gypsy apply the maxim
while learning C#.
Now, the mere fact that you are reading this means that you are interested in learning something
new. However, there is a great deal of difference between a person who wants to read a book and
the person who just wants a book to read. We hope you belong to the former category.
Though we attempt to infuse a certain degree of humour in our writing, please do not buy this
book for its jokes. This is no coffee table book or even bedtime reading. This is a book, a
medium, which we hope will do the serious job of teaching the reader a new programming
language.
And how do we propose to go about it? Just like when you eat, no matter how delicious the food
in front of you is, you have to consume it, one mouthful at a time. You just cannot eat it all at
once, can you?
Similarly, when learning, it is always better to take small steps - one concept at a time.
Sometimes, we even repeat the same concept several times, in different ways. For we firmly
believe that if you do the little things well enough, big things will come to you asking to be done.
Incidentally, the entire C# software is available on the Microsoft site, downloadable free of
charge. Detailed instructions are given on the site along with a set of FAQs.
Well, that's that. We agree, it is tough to climb the ladder of success, especially if you're trying to
keep your nose to the grindstone, your shoulders to the wheel, your eye on the ball and your ear
to the ground. Precisely the reason why some people do not recognise opportunity - it often
comes disguised as hard work.
This book presents you with precisely such an opportunity. We hope you grab it with both hands!
Acknowledgements
I wish to thank a number of people who gave me support, new ideas and
First and foremost, thanks to Manish Jain, BPB publication for publishing the book.
Special thanks to my co-authors, Sonal and Sandeep, who have put in their very best in the work
assigned to them as without them and their efforts the book would have never seen the light of
day.
Thanks to my cover designers, Altaf Hemani and Kishore Rohra, for designing the cover in a
very short notice.
Thanks to Manish Purohit for putting in all the time he had to verifying the code with the
explanation, testing all the applications in the book and updated them to work under the Release
version of the product.
To, Pradeep Mukhi and Shivanand Shetty, who made it simple for me and my co-authors to
come up with the book.
A long list of friends and my family need a mention here for their patience and cooperation on
this book while it was being written.
-Vijay Mukhi
1
Getting Started
C# is pronounced as "C sharp". It is a new programming language that enables programmers in
quickly building solutions for the Microsoft .NET platform.
Today, one cannot, just cannot, afford to ignore C#. It is our considered opinion that it holds
immense promise and we are going to try our best, through this book, to help you realize its
potential. Be assured, we are not going to teach you just another programming language. It is our
intention to help you apply C# in practical situations, to actually implement your newly acquired
knowledge on the Net.
With this brief introduction, let us embark on a path that will take you to new adventures in the
world of Internet. In this chapter, we will get you started with C# by introducing a few very
simple programs. For remember, even a journey of a thousand miles must begin with a single
step.
We assume that you have no prior knowledge of any programming language. But before we get
ensnared in the fascinating world of C#, let's make a directory where we will save all our work.
In order to do so, click on Start, Programs, then go to Accessories and select Command Prompt
(Windows 2000) or the MS-DOS Prompt as it is called in Windows 98. Once you are at the
command prompt create a directory called csharp (md csharp) and change to this directory (cd
csharp). Now type the command 'edit a.cs', which will open the MS-DOS editor - the world's
simplest editor.
C:\csharp>edit a.cs
Yes, we very well understand how you must be yearning to write your first C# program and get it
working. But before we do that, there are certain intricacies that you must understand. What a.cs
refers to is called the filename or program name. Here we have named our file or program a.cs.
Why a.cs? Well, before we began writing this book, we consulted a renowned astrologer who
predicted that if we named our first file a.cs then great luck would be showered on us. Not
wanting to quarrel with the stars, we named our file a.cs. But you are free to go ahead and call
your file any name you want. But then do so at your own risk! Remember, forewarned is
forearmed!
Jokes aside, 'cs' is the extension used for C# files. They say of all the things you wear, your
expression is the most important. Notwithstanding this, one does look more dapper in a suit
rather than a vapid shirt and trousers. Similarly, though it is not mandatory to provide the
extension 'cs', you can make a filename seem more impressive by giving it an extension. To
reiterate, you could have given the extension say 'ws' too; it does not matter. But absent minded
as we are, it is more prudent to give appropriate extensions while naming files.
a.cs
class zzz
Here we start with the word class zzz followed by open and close curly braces. A class is nothing
but a collection --- a collection of everything that the programming language contains. It is like a
packet or a container, which can hold anything. Hence everything in a C# program must be
enclosed within a class. We have named our class zzz, again you could have named it anything
else but if you would rather follow our naming convention (for reasons well amplified above!),
name it zzz.
Now for the part that you've been eagerly waiting for!
In order to execute the program, go to the File menu, and click on Exit. You will get a dialog box
asking you whether you want to save the file or not, say yes. Now that we have typed and saved
our file we need to execute it. The compiler creates executable code. The command used to call
the C# compiler is csc followed by the program name. Since our program name is a.cs, the
command csc a.cs will call the compiler. A compiler is a program which understands the C#
programming language. Thus the word class is part and parcel of the C# language. Microsoft lets
you freely download the C# compiler from their web site :
http://msdn.microsoft.com/library/default.asp. Select .Net Framework SDK under .NET
Development. Choose the Download option to download the sdk which is around 127 MB large.
Install the product on your machine cause if you don’t, none of the following programs will
work. Also, Internet Explorer 5.5 and Microsoft Data Access Components(2.7) must be installed
prior to installing the sdk
C:\csharp>csc a.cs
You will see the following output on your screen in the dos box.
Microsoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914] Copyright (C)
Microsoft Corp 2000-2001. All rights reserved.
error CS5001: Program ‘a.exe’ does not have an entry point defined
Just as the excitement was beginning to grow, our program returns with an error message. Don't
worry, occasional failure is the price of improvement.
The error message starts with an error number CS5001 followed by a cryptic message, which we
do not understand.
We are aware of the fact that everything has a beginning and an end. Similarly, a C# program
also has a start and an end. Ah! Now you realize why the error occurred. We forgot to tell C#
where to start executing our program from. This starting point is also called an entry point.
You can specify the entry point by adding static void Main() to your program, just as we have
done below.
a.cs
class zzz
Compile the above code giving the command as csc a.cs. Voila! Now no errors.
The compiler will now generate an exe file called a.exe. Giving the command dir at the
command prompt will prove the same. On keen observation you will notice that among the 2
files listed, there is a file by the name a.exe. Simply type 'a' at the command prompt, your
program will now be executed!
C:\csharp>a
The program will run but shows no output on our screen. But, at least we get no errors.
The words, static and void, will be explained to you a little later, in the right perspective. Thus if
you had felt the beginnings of a massive headache, you can breathe easy! Anything followed by
'(' and ')' brackets is called a function. So, it is obvious that Main is nothing but a function. Here
we are creating a function called Main. It is followed by the '{' and '}' curly braces. Note that the
letter M in Main is capital. Thus C# requires a function called Main, which is the first function
that will be executed. Failure to do so will result in an error. Ergo, whenever you see a word
beginning with an open '(' and close bracket ')', C# and most other programming languages call it
a function. The { signifies the start of a function and the } signifies the end of the function. The
guys who designed the language decided to use {} braces instead of start and end. When you tell
people that you are learning a programming language, you are actually learning to use {} braces
to specify the beginning and end of a function. These rules have to be remembered by rote. You
have no choice.
Now we are ready to add some code in our program. In order to do so, add the line
WriteLine("Hell"), just as we have done below.
a.cs
class zzz
WriteLine("Hell")
Oops! The astrologer had promised showers of luck! Even a drizzle seems far away! Executing
the above program results in the following error:
Compiler Error
The error message begins with the file name, a.cs followed by round brackets containing the line
number and the column number, where the error occurred. The compiler informs us that it found
an error on line number 5 and column number 18 and it expects a ;.
As the cliché goes, when the going gets tough, the tough get going. So we shouldn't lose heart as
yet; let's understand why this error occurred.
Look at WriteLine within the brackets; doesn't it ring a bell? Isn't WriteLine a function too? But
here we do not have the curly braces following it. This is because here we are not creating a
function like we created Main. Then what is it that we are doing? We are calling a function called
WriteLine, which has already been created.
The error says ';' expected. Though it is obvious to us that the statement has ended, unfortunately
for you and me, C# isn't so smart. It requires a semi-colon to tell it loud and clear that the
statement has ended. Merely pressing enter does not suffice. Though not so for other
programming languages, in C# it is mandatory to use a semi-colon. Alas! Each programming
language has its own rules!
At this juncture, an intelligent question would be - But why semi-colon? Why not any other
punctuation mark? We don't know for sure but perhaps the developers of C# were asked to select
a character that would indicate the end of a statement. The non-compromising species that we
are, they could not arrive at a consensus. Result? Grandma's recipe of eene meene mina mo!
When they stopped, their finger was pointing at the semi-colon, hence they selected the same.
Thus rules are rules; as preposterous as they may sound, they must be followed.
Add the semi-colon and execute the program. Also languages like ABAP/4 from SAP ends lines
with a dot (full stop). Thus we expect to understand programming in English. Every language
expects an end of statement/command terminator. Every language expects a symbol to denote
when the user has finished saying something. In C# it is a ; , other languages have their own
symbols. Remember that the statement or function WriteLine was written on line number 5
hence the error reported line number 5.
a.cs
class zzz
WriteLine("Hell");
Compiler Error
a.cs(5,1): error CS0103: The name 'WriteLine' does not exist in the class or namespace 'zzz'
Another error! We are extremely disappointed, it just doesn't seem our day. However we firmly
believe that you may be disappointed if you fail, but are surely doomed if you don't try. And we
don't want to be doomed do we? So let's keep our chin up and carry on.
But you know what's most irritatingly bothersome? Why are all error messages so difficult to
understand? Well, with the experience that we have gained over the years we have learnt that if
error messages could be understood then we wouldn't get them in the first place!
In any case, to be truly candid, the error occurred because we pulled a fast one on you! We are
calling a function WriteLine but in fact no such function exists. The accurate name of the
function is not WriteLine but System.Console.WriteLine. Microsoft is known to fancy big names
and here is one more example. In any case, let's execute the program.
a.cs
class zzz
System.Console.WriteLine("Hell");
Output
Hell
Finally, no errors! Surely you feel blessed! It displays the word 'Hell', and we suspect that's
exactly what you are going through right now. But if you follow our programs step by step we
assure you that heaven is not too far away.
Now remove all the extra spaces and 'enters' from your program, just as we have done below and
compile the program again.
a.cs
class zzz {static void Main() {System.Console.WriteLine("Hell");}}
Output
Hell
You will notice that doing so does not give any errors. Just like the previous program, it displays
'Hell'. The C# compiler is not affected by it. But using spaces and 'enters' definitely make your
program neater and thereby more readable. The effect is especially appreciated in large programs
and more so when someone else has to go through them. Having said that, anyway, the first thing
that C# compiler does is removes all the spaces and enters from the program code you have
written.
a.cs
class zzz
System.Console.WriteLine("Hell");
System.Console.WriteLine("Bye");
Output
Hell
Bye
On executing this program, 'Hell' and 'Bye' are displayed on two separate lines. Here, we are not
required to give anything that has the 'enter' effect, WriteLine automatically prints on a new line
each time. Which simply means you can call a function as many times as you like.
In the next illustration, let's understand how functions are called and created. Here we are calling
a function abc().
a.cs
class zzz
abc();
Compiler Error
a.cs(5,1): error CS0103: The name 'abc' does not exist in the class or namespace 'zzz'
On executing this program you will get, what else, but an error. Peter Drucker, the famed
management guru had once said that the better a man is, the more mistakes he will make, for the
more new things he will try. So there you go - next time you encounter an error, simply tell
yourself that you have just become better at whatever you are doing.
In any case, the error says that abc does not exist. Here we are calling a function called abc(), but
where is abc() defined or created ? It is not a function that has been provided by C# to us free of
charge. It is our own homegrown function that we are calling. The lesson here is that we cannot
call a function without first creating it. So, to rectify this error we will first create a function abc.
Our next example demonstrates this.
a.cs
class zzz
abc();
System.Console.WriteLine ("Hell");
Output
Hell
In the function abc, we have included only one statement- WriteLine within the curly braces. The
'{' and '}' braces indicate the beginning and the end of this function. Alternatively, a function can
contain millions of lines of code that will be executed when the function is called. Since
everything is contained in a class, our function abc is also created within the class zzz but outside
Main. But the function is called from Main. On executing the program, 'Hell' is displayed. This is
because we have included the code for 'Hell' to be displayed in the function abc. Thus, when the
control reaches the line abc(); it searches for that function and executes the code within that
function. We will explain static and void later as promised.
You can call as many functions as you like from your program. But you must remember to
separate each one with a semi-colon. The next program illustrates this.
a.cs
class zzz
abc();
pqr();
abc();
{
System.Console.WriteLine ("I am ABC");
Output
I am ABC
I am PQR
I am ABC
At first the function abc is called, then pqr and then again we are calling abc. On executing this
program 'I am ABC', 'I am PQR' and 'I am ABC' will be displayed. This is because we have
included the code for these lines to be displayed in the respective functions.
In the following program we are calling the function pqr from abc and not from Main.
a.cs
class zzz
abc();
{
pqr();
Output
I am PQR
I am ABC
In the function abc, we are first calling pqr and then displaying 'I am ABC' using the WriteLine
function. Hence, first 'I am PQR' is displayed and then 'I am ABC'. Thus, this program
demonstrates how functions can be called from other functions.
Now that we have created our own functions abc and pqr, we have an intuitive understanding of
how C# created the function System.Console.WriteLine. The next program uses the printing or
formatting capabilities of the WriteLine function.
a.cs
class zzz
System.Console.WriteLine("100 {0}",100);
}
Output
100 100
The zero in the curly braces means that after the first comma there is some value and that it
should display this value. You cannot differentiate between the two 100's. The {0} is replaced
with 100, the number, which follows the first comma. If you don't like the number 100, use the
number 420 instead. We won't mind - at least it's something that some of you can easily identify
with!
a.cs
class zzz
System.Console.WriteLine("100 {0},{1}",100,200);
Output
100 100,200
Here the {0} is replaced with 100 and {1} is replaced with 200. The comma (,) separates the two
numbers. Thus {0} means the first number and {1} means the second. C# likes to count from
zero and not one.
a.cs
class zzz
{
ii;
ii=20;
System.Console.WriteLine ("{0}",ii);
Compiler Error
a.cs(5,1): error CS0201: Only assignment, call, increment, decrement, and new expressions can
be used as a statement
a.cs(5,1): error CS0103: The name 'ii' does not exist in the class or namespace 'zzz'
a.cs(6,1): error CS0103: The name 'ii' does not exist in the class or namespace 'zzz'
a.cs(7,33): error CS0103: The name 'ii' does not exist in the class or namespace 'zzz'
Experience is knowing a lot more of things you shouldn't. But now that you have decided to
embark upon this book, let's see what you should know!! Executing this program results in a
large number of errors as shown above. Let's understand the rationale behind it. Here we have
included a strange word --- ii. This word ii is being given a value of 20 as ii=20. But C# is a shy
program. It does not speak to strangers! Here ii is nothing but a stranger to C#. C# does not know
who or what ii is. You can't just write words that you feel good about. So, in order to rectify this
error we must tell C# who ii is.
a.cs
class zzz
int ii;
ii=20;
System.Console.WriteLine ("{0}",ii);
}
Output
20
Note that in this program we have added the word int before ii. The word int indicates that ii is
an integer or a number. Each time we create our own word like ii, C# wants to know what we
will store in this word. We will understand this better and in totality in just a little while. Here we
are initializing ii to 20 or giving it a value of 20 by writing ii = 20. Why 20? Maybe because we
are feeling very youthful today! Following this we have the WriteLine function. Now, it is a
known fact that jaggery is a good substitute for sugar. Similarly, in C# you can substitute a
number with a word. So, in WriteLine we have used the word ii instead of a number. The word ii
gets replaced with the value 20. So, on executing the program, the number 20 is displayed.
You may be wondering as to why should you ever use a word when you can use a number
directly. Our next program will enlighten you on this.
a.cs
class zzz
int ii;
ii=20;
System.Console.WriteLine ("{0}",ii);
ii=30;
System.Console.WriteLine ("{0}",ii);
ii=ii+10;
System.Console.WriteLine ("{0}",ii);
ii=ii+1;
System.Console.WriteLine ("{0}",ii);
ii++;
System.Console.WriteLine ("{0}",ii);
Output
20
30
40
41
42
The first three lines of this program are identical to those of our previous one. Thus in the first,
the WriteLine function will display the number 20. Thereafter, by saying ii=30 we are initializing
the word ii to a value 30. In effect, we are changing the value of ii from 20 to 30. So, WriteLine
will now display 30.
Thus, a variable is a word whose value varies or changes. ii initially had a value 20 that changed
to 30.
Coming back to what the word int means- when you say int, int means integer or number. When
we say int ii, it means that the variable ii will store a number. ii could also be used to store the
letters of the alphabet like the names of people. It could also store a date. But here we wanted ii
to store a number. So, we have to tell C# in advance as to what the variable is going to store.
Hence we say int ii. C# understands the word int as int is a part of the C# programming
language.
The variable ii started with the value 20 and is now holding a value 30. In the next line we have
ii=ii+10. The 'equal to' sign makes this statement look complicated. To avoid confusion, always
start by looking to the right of the 'equal to' sign. To the right of the equal to sign we have ii+10.
Since ii is holding the value 30, ii+10 is read as 30+10, which evaluates to 40. Hence ii=ii+10
will now be read as ii=40. This value 40 is given to the variable on the left-hand side. Now that ii
has a value 40, WriteLine will display 40. Similarly, we say ii=ii+1. Here the value of ii is
incremented by one. And the new value of ii, which is 41 will be displayed by WriteLine. In the
next line we have ii++. Note that ii=ii+1 and ii++ do the same thing. They both increment the
value of ii by 1. Hence WriteLine will now print the number 42.
This is a big problem with programming languages. As there are many ways to skin a cat, there
are also many ways to increase the value of a variable. So ii = ii + 1 and ii++ do the same thing.
A programmer thus has the choice to use either of the two ways to do the same thing. There you
go ---as you can see, first time programmers have unfortunately a lot to learn.
In daily life, a hundred different people can do the same chore in a hundred different ways.
Similarly, in programming there is more than one way of doing a particular thing. Programming
becomes a problem because of redundancy. Since there are two ways of doing the same thing
you have to learn them both and that can be very confusing. Of course, it is at your discretion to
choose the method you are comfortable with. Henceforth, even though there may be many other
ways of doing a particular thing, we will teach you only one method that we find appropriate.
A variable is a word that stores a value. This value can be changed at will by the programmer.
Wherever we can use a number, we can also use a variable.
The next program may seem alien to you. This is because it speaks the truth. If it finds that a
condition is true it outputs true and if it finds the condition to be false it outputs false. Very
unlike some of you, who would do just the opposite!
a.cs
class zzz
Output
True
False
False
True
False
True
Here the first line says WriteLine("{0}", 5 > 2); Is 5 > 2 ? Yes. So the condition 5 > 2 evaluates
to true. Hence the {0} in WriteLine is replaced with True and the WriteLine function displays
True. 5 > 2 is called a condition. A condition is like a question which has to result in a yes or no
or a true or false. In this case the number 5 is greater than the number 2 and hence the function
evaluates to true. C# understands the words true and false.
In the second WriteLine we have the condition 5 < 2. Is 5 < 2? No. So the condition 5 < 2
evaluates to false and hence WriteLine displays False. Similarly, the next condition 2 < 2 is not
true and hence False is displayed.
In the next statement we have 2 <= 2. Here the first sign being '<' it is first checked whether 2 <
2? No, 2 is not less than 2. So then the second sign '=' is checked i.e., whether 2 = 2? Yes. So the
condition 2 <= 2 evaluates to true and WriteLine displays True. <= is thus two conditions in one .
In the next WriteLine we have the condition 2 != 2. '!=' means 'not equal to'. But 2 is equal to 2,
hence the condition evaluates to false and False is displayed. The comparison is false, therefore
the condition is false.
In the last statement we have the condition 2 != 3. Is 2 != 3? Yes 2 is not equal to 3, so the
condition evaluates to true and True is displayed. This True and False is a special data type in C#.
It is called 'Bool' or boolean derived from Boolean algebra.
a.cs
class zzz
{
bool ii;
ii=true;
ii=false;
Output
True
False
In our previous programs we used the data type int for the variable ii. This meant that ii could
store integers or numbers. Similarly, you can now initialize ii to either true or false. This is
possible by using the data type bool for ii. A data type means the type of data a variable can hold.
Therefore, here we are saying bool ii. In the first case we are initializing ii to true. So in
WriteLine, {0} is replaced with true. In the second case ii is initialized to false and {0} is
replaced with false.
In a gist, we now know that variables can be either bool or logical or they can contain the words
True or False. Also, variables can also contain numbers.
a.cs
class zzz
ii=10;
jj=false;
Compiler Error
If you want the rainbow, you gotta put up with some rain. So let’s understand the reason behind the errors.
Here C# is internally saying that it distinguishes between data types. In that sense C# is very petty about
what values you give to variables. Bool can't mix with int and vice versa. Since ii is a bool you can't
initialize it to 10, which is a number. C# is very strict about this. And because jj is an int you can't
initialize it to false. So you have to be very careful about how you initialize your variables. After all it
doesn't make sense to ask someone who is good at driving to teach computers and vice versa. Everyone
has his or her place in life. Similarly, variables also have their place. Hence a variable declared as a bool
can only have values true or false. Similarly, int can have only numbers or integers, it cannot take true or
false values.
a.cs
class zzz
bool ii;
ii=6 < 7;
Output
True
Here ii is a variable of type bool. In the next statement we have ii = 6 < 7. As you already know,
in such a case you should start by looking to the right of the 'equal to sign'. Because 6 is less
than 7 the condition evaluates to true and ii will be initialized to true. Hence {0} is replaced with
the value of ii, which is true and True is displayed.
C# is called a strongly typed language because you cannot initialize a variable of type int to a
variable of type bool. The reason C# is very strict about this is because this system eliminates a
large number of sloppy programming errors. Some languages like C on which C# is based on do
not care what values you initialize your variables to. C# is stricter than even Java. In some ways,
it's like your mother when it comes to telling you what you are doing wrong in life. Thus it is
extremely difficult to make dumb errors in C#. Remember when you are writing code in C#, the
compiler is always peering down your shoulder making sure you do not get away with any
errors.
If Statement
So far the code that we have written is rather useless. This is because it always gets executed.
Life is enjoyable only because it is unpredictable. We don't know what tomorrow is going to
bring. Variety is the spice of life! Similarly, we would like to write computer programs, which
add spice to programming. We want to write programs that behave differently depending upon
different situations or circumstances. And this can be achieved with the help of the if statement.
So fasten your seatbelts and get set to ride!
The next few programs will demonstrate the usefulness and application of the if statement.
a.cs
class zzz
if ( false )
System.Console.WriteLine ("Hi");
}
Compiler Warning
In this program we have included the word 'if' followed by false in round brackets. This is the if
statement and its syntax. Syntax is the grammar in writing. Thus we have no choice but to abide
by the rules. It is called a statement because anything that C# recognizes is called a statement.
When you run this program, you realize that there is no output. So this program will simply
display nothing. Now you know why we get the above warning as our code will never get
executed.
The if statement lets you include decision making in your program. It decides whether to execute
the next line or not. When the if statement evaluates to false then the next line is ignored. The if
statement brings with it the power to decide whether certain code should be executed or not.
a.cs
class zzz
if ( false )
System.Console.WriteLine ("Hi");
System.Console.WriteLine ("Bye");
Output
Bye
The if statement looks at the immediate next line, it doesn't look at the line after that. Since the if
statement influences only one line, you will see only Bye displayed and not Hi. Same warning
again.
But if you want both the statements to be affected by the if then enclose them within curly
braces. This is illustrated below.
a.cs
class zzz
if ( false )
System.Console.WriteLine ("Hi");
System.Console.WriteLine ("Bye");
Here we have included both the lines of code within the braces. Now the if statement will affect
both the lines of code. The condition being false, nothing is displayed. Thus, the if statement
gives us the option to execute or not to execute a certain piece of code.
If we always use false then the code will never be called. But what did we tell you about
conditions? They return either true or false. So, in the next program we have 3 > 8 as the
condition. Since 3 is not greater than 8 the condition evaluates to false. Since there are no curly
braces, only the next line is affected by the if statement. Hence only Bye is displayed.
a.cs
class zzz
{
static void Main()
if ( 3 > 8 )
System.Console.WriteLine ("Hi");
System.Console.WriteLine ("Bye");
Output
Bye
Let's look at another variation of this program. Now, the interesting part is that wherever you can
use a condition you can also use a variable which is of type bool, which we know evaluates to
either true or false.
a.cs
class zzz
bool ii;
ii=true;
if ( ii )
System.Console.WriteLine ("Hi");
System.Console.WriteLine ("Bye");
}
}
Output
Hi
Bye
Here the variable ii is declared as a bool and then initialized to true. In the next line we have if
(ii). The variable ii holds the value true and hence the if condition evaluates to true. The
condition being true both Hi and Bye are displayed. Note that here both the statements are
included in the curly braces resulting in both the statements being affected by the if statement.
Thus the if statement is affecting a block of statements. Declaration is another way of saying that
we are creating a variable.
In the following program we have an if with the else. If the if condition evaluates to true then the
statement following it is called but if it evaluates to false then the else is called.
a.cs
class zzz
if ( false )
System.Console.WriteLine ("Hi");
else
System.Console.WriteLine ("Bye");
Output
Bye
Here, since the condition evaluates to false the else is called and hence Bye is displayed. Thus
the additional else statement specifies a statement that is executed when the condition is false.
This construction covers all possibilities, as a condition can be either true or false. In an 'if-else'
construct one of them have to be executed. Computer programs are said to be made intelligent
because of the if statement. The more the use of the if statement, the more intelligent your
program becomes. The if statement is one of the main building blocks of any programming
language. Thus all programming languages have to have a if statement.
Loops
The if statement is the cornerstone of programming because it lends intelligence and a decision
making power to the language. The second important constituent of any programming language
is a looping construct. In a program many times you would need to repeat instructions. In C#, the
for statement is one form of a loop that lets you repeat statements. However, as we already know,
a statement can also be a block of statements, thus it also allows repetition of multiple
statements.
a.cs
class zzz
int ii;
Output
Hi 1
Hi 2
Hi 3
Hi 4
Hi 5
The for has 2 semicolons as part of its syntax or rules. The statement up to the first semicolon is
executed only once. For the first time and only the first time ii is initialized to 1. Remember up to
the first semicolon the statement is executed only once. The statement enclosed within the first
and second semicolon is a condition. The condition checks whether ii <= 5 evaluates to true.
Since this condition evaluates to true, the statement within the open and the close braces gets
executed. If the condition evaluates to false, the statement is ignored and the loop terminates.
The variable ii has a value 1 which is less than 5, so System.Console.WriteLine will be called
which displays 'Hi 1' as the value of ii is 1. After the statement gets executed, the last part of the
for i.e. from the second semicolon to the closing bracket gets executed. ii++ will increase the
value of ii by 1, making it 2. The condition is checked again, is 2 <= 5. The answer here is true,
so 'Hi 2' is displayed. And this roller coaster goes on till the condition is false. When ii has the
value 6, the condition checked is, is 6 <= 5. The answer being false, the for terminates. This is
how the for statement enables the repetition of code.
a.cs
class zzz
int ii;
Output
Hi 1
Hi 2
Hi 3
Hi 4
Hi 5
Hi 6..
In this program we have two WriteLine statements. The for loop follows the same rules as the if
statement. Thus in absence of curly braces the for loop will affect only the immediate next
statement. Therefore, the for loop will print numbers from 1 to 5 along with hi. The moment the
for loop terminates, ii with the dots will print Hi 6... This goes to prove that when ii has a value
six, the for loop will terminate.
The following program demonstrates how the for loop enables repetition of multiple statements.
a.cs
class zzz
int ii;
}}}
Output
Hi 1
Hi 1..
Hi 2
Hi 2..
Hi 3
Hi 3..
Hi 4
Hi 4..
Hi 5
Hi 5..
Here, both the WriteLine statements are enclosed within curly braces. Therefore, both the
statements are affected by the for loop. Hence, in this case, each number is displayed twice along
with Hi, once without the dot and once with the two dots.
a.cs
class zzz
int ii;
ii=1;
while ( ii <= 5 )
}
}
The while loop takes a condition, hence the variable ii is initialized to 1 before entering the loop.
The condition checks whether ii <= 5 evaluates to true. Currently the value of ii is 1. The
condition evaluates to true and the statement within the curly braces is executed.
System.Console.WriteLine is called with Hi and the value of ii. Note that here we are not
changing the value of ii within the loop. Since the value of ii remains 1 the condition always
evaluates to true and the loop will go on forever, indefinitely.
We can't have anything go on forever, can we? There has to be a stop to it somewhere! Our next
program will resolve this problem.
a.cs
class zzz
int ii;
ii=1;
while ( ii <= 5 ){
ii++;
Output
Hi 1
Hi 2
Hi 3
Hi 4
Hi 5
This program is similar to the previous one. The only change that we have made is that we added
the line ii++; thus for the first time Hi 1 is displayed. Then the moment ii++ is encountered the
value of ii is incremented by 1, making it 2. Then the condition, 2 <= 5, is checked. The
condition being true, once again we enter the loop and Hi 2 is displayed. This will go on until ii
becomes 6. Once ii is 6 the condition evaluates to false and the loop terminates.
Your mind may ponder over the question, "Should I use a for or a while?' The for loop is similar
to the while loop. To answer your question in the most simple manner "On Mondays,
Wednesdays, Fridays use for and on Tuesdays, Thursdays, Saturdays use while. Sundays we
assume no one writes code". Alternatively "Toss a coin, heads use while, tails don't use for" ;-)
In other words, it is at your discretion to use the one you are comfortable with. Once again C#
offers you multiple ways of doing the same thing.
a.cs
class zzz
int ii;
ii = abc();
System.Console.WriteLine("hi {0}",ii);
System.Console.WriteLine("abc");
return 100;
}
Output
abc
hi 100
executing the line ii=abc(); Doesn't the right hand side of the statement ring a bell? Aren't we
calling the function abc() ? Hence at this point the control passes to the function abc().
In the function we have the WriteLine statement, which prints 'abc'. Thereafter, we have a return
statement. It says return 100. In effect, the function abc() is returning a value 100. Thus the
statement ii = abc(); will now be read as ii=100. Now that ii has a value 100, {0} in WriteLine is
replaced with 100 and in turn 100 is displayed.
a.cs
class zzz
int ii;
ii = abc();
System.Console.WriteLine("hi {0}",ii);
System.Console.WriteLine("abc");
return 100;
}
Compiler Error
a.cs(12,1): error CS0127: Since 'zzz.abc()' returns void, a return keyword must not be followed
by an object expression
Executing the above program results in errors. Here we have static void abc(). What static
means, we will explain a little later. It is with the intention to enable you to learn better, so please
bear with us. The word void means nothing. So by saying void abc() we are saying that the
function abc() does not return any value. Functions may/maynot return values. Earlier abc
returned an int. When a function returns void as in this case, we are saying that abc cannot return
a value. But in the function code we have written return 100. Therefore, because of this
contradiction we get the error. Note that in the previous program we did not get an error. This
was because we had said static int abc(). Here int signifies the return type of the function. Since
the function returns a number we used int.
In our next example we have made only one addition i.e. we have added
System.Console.WriteLine("Finish"); after the return statement.
a.cs
class zzz
int ii;
ii = abc();
System.Console.WriteLine("hi {0}",ii);
{
System.Console.WriteLine("abc");
return 100;
System.Console.WriteLine("Finish");
Compiler Warning
Output
abc
hi 100
On executing this program, you will find that the output is the same as the previous program. To
your amazement you do not see the word 'Finish' displayed. No, it is not because C# doesn't like
you. The reason is that anything after the return statement is ignored.
Thus, you may have a hundred WriteLine statements after the return statement but they will all
be ignored. Simply stated, no lines after return statement will get called. That is why the C#
compiler, courteous as it is, gives you a warning and not an error.
You have already learnt about two data types, int and bool. Our next program introduces a new
data type 'string'.
a.cs
class zzz
string s;
s= "hell";
System.Console.WriteLine(s);
Output
hell
In this program, the variable s is declared as a string. This implies that s will store mainly letters
of the alphabet. Then s is initialized to hell, which is nothing but a collection of the letters of the
alphabet. Note that all strings have to be enclosed within double inverted commas.
System.Console.WriteLine displays the value of the variable s, which is 'hell'. Earlier we wrote a
string in double inverted commas directly. However, this time we are using a variable name
instead.
Now we know the first parameter to the WriteLine function is a string. We earlier named our
variable ii and now we have called it s. Actually, we name our variables depending upon the time
we write our programs. You decide your own rules for naming variables. Anything you enclose
in double quotes is called a string. System.Console.WriteLine is smart enough to display strings,
bools and int.
a.cs
class zzz
string s;
s= "hell";
Output
hell
This program is exactly like the previous one, the only difference being that we have used {0}
instead of writing only s. Here the {0} is replaced with the value of s, which is 'hell'. Thus, using
the {0} is preferable as it understands a large number of data types and how to display their
values.
Consolidating, our next example incorporates all the data types that we have learnt so far.
a.cs
class zzz
string s;
int ii;
bool jj;
ii=10;
jj=false;
s="hell";
Output
10 False hell
Here the variable s is declared as a string. Then ii is declared as int and jj is declared as bool. In
the next three statements we are initializing each of the variables. ii is initialized to 10, jj is
initialized to false and s is initialized to hell. Now, with the help of a single WriteLine statement
we are displaying the values of all the variables. {0} is replaced with 10, {1} is replaced with
False and {2} is replaced with hell. This goes to prove that all the data types can be displayed
together, in a single WriteLine statement. Thus, C# allows all the data types to co-exist in
harmony. Now only if the people of our country could do the same!
By now you are familiar with functions and how functions are called. The next program
illustrates how parameters are passed to functions.
a.cs
class zzz {
abc(10,false,"hell");
Output
10 False hell
In this program, we are calling the abc function with three things, with three parameters. The first
is a number, the second is a logical value and the third is a string. So, we are passing the values
10, false and hell to the function abc(); These values must be stored somewhere, but where?
When we create the function abc we have to state the names of three variables along with their
respective data types. This is because the values that we pass will be stored in these variables.
Hence we have the variables i, j and s. These are then displayed using WriteLine. Therefore, it
will output 10, False and hell. This is how parameters are passed to functions in C#. Remember
you decide what names to give to variables. Parameters passed to functions are also variables.
a.cs
class zzz {
abc(10,false);
Compiler Error
On compiling this program you will encounter the above error. Here we are calling abc with only
two parameters, 10 and false. Whereas the function abc is actually created with three parameters.
We are passing an erroneous number of parameters, hence the error. Lesson? One must pass the
same number of parameters that the function has been created to accept. A mismatch between the
number of parameters being passed and those being accepted will definitely assure you of an
error. Thus as before, C# does a large number of error checks on your code. For, if it allowed the
above function call to go ahead, what would the value of the third parameter s be?
Now change the order of the values that are being passed. Your abc function should look like
this- abc("hell",10, false);
a.cs
class zzz
{
static void Main()
abc("hell",10,false);
Compiler Error
a.cs( 5,1): error cs1502: The best overloaded method match for 'zzz.abc(int, bool, string)' has
some invalid arguments
a.cs( 5,5 ): error cs1503: Argument '1': cannot convert from 'string' to 'int'
a.cs(5,12): error cs1503: Argument '2': cannot convert from 'int' to 'bool'
a.cs(5,15): error cs1503: Argument '3': cannot convert from 'bool' to 'string'
On executing this program you will be faced with the above errors. These errors have resulted
due to a data type mismatch. It is somewhat like putting a round pole in a square peg! How is it
going to fit?
While calling the function abc() the first parameter that we are passing is the word "hell". But the
function abc() has been created to accept the first parameter as an int. Remember we told you,
not so long ago, that C# distinguishes between data types. Thus you can't store a string in a
variable of type int. Similarly, the value 10 cannot be stored as a bool and false cannot be stored
as a string. Therefore, not only should the number of parameters being passed and accepted be
the same but also their data types must match.
Like oil and water do not mix, in the same way you cannot give C# an int when it wants a string.
As said earlier, some languages are more forgiving then C# due to which the programmer makes
more mistakes in them.
a.cs
class zzz
abc();
class yyy
System.Console.WriteLine("abc");
Compilation Error
a.cs(5,1): error CS0103: The name 'abc' does not exist in the class or namespace 'zzz'
In this program we have created another class called yyy. We can have as many classes in one .cs
file as we like. This program now has two classes, zzz and yyy. The class zzz has a function
called Main. Main denotes the starting point of our code and as such is the first function to be
called. The class yyy contains a function called abc. Here we are calling the function abc by
saying abc(); in class zzz. But class zzz does not have any function by the name abc. Merely
giving abc(); encourages C# to assume that abc() exists within the class zzz. But our abc function
is contained in yyy. Hence we get an error as we are trying to call a function that exists in
another class.
But we are adamant! We want to use the abc function that yyy has. It's human tendency to want
things that others have! So, in the next program we are calling the function abc in the class yyy
by writing yyy.abc();
a.cs
class zzz
yyy.abc();
class yyy
System.Console.WriteLine("abc");
Compilation Error
When we say yyy.abc(); why the dot? yyy is the name of the class and abc() is the name of the
function . Each of these names can be as large as you want, so to separate them a dot is used.
Thus when you want to access a function that belongs to another class you can do so by
specifying the class name and function name separated by a dot. The dot is like the semicolon.
The designers of the language wanted some character as a separator between class name and
function name, they chose the dot, they could have also chosen the semicolon again.
You will now realize why we say Console.WriteLine. Obviously, it means that Console is a class
and within the class Console there is a function called WriteLine.
But to your dismay, on executing this program you still get an error. Well, few people get what
they want, however fewer still want what they get! You may want a particular thing but you will
not get it unless the other party gives you the permission to take it, use it or share it. Your only
other option is to put up a fight!
We get an error here because we haven't used the word public. The whole idea behind C# is its
usability on the net. And the only way you can use it on the net is by having security precautions.
So in C# the default rule is - you can't use anything unless explicitly granted permission. Next
question. How do you grant the necessary permission?
Being its non-violent self, C# grants permission by using the word public. When we say public,
we mean the world at large. So by starting with the word public we are saying that the whole
world is now allowed to use this function as we are explicitly granting you rights. If you don't
use the word public it will give you an access error.
To rectify the error, add the word public just as we have done below.
a.cs
class zzz
yyy.abc();
class yyy
System.Console.WriteLine("abc");
Output
abc
Finally, we have the correct code! See, one of life's greatest ironies is the fact that when you
finally master a tough job, you make it look easy!! By using the word public in front of the
function abc, we can now call it from zzz by specifying yyy.abc(); Now that the function is
called, WriteLine displays 'abc'.
a.cs
class zzz
yyy.abc();
abc();
zzz.abc();
System.Console.WriteLine("abc in zzz");
class yyy
System.Console.WriteLine("abc");
}
Output
abc
abc in zzz
abc in zzz
Now we go a step further. In the above program we have two abc functions, one in class zzz and
one in class yyy. If you want to call the one in yyy then you say yyy.abc(); but if you want to call
the one in zzz then you say zzz.abc() or abc(). The function abc(), by itself, will ask which class
is it? Since abc() is in zzz itself, C# assumes it to zzz.abc(); By implication, if the function exists
within the same class, it is optional to preface the function with the name of the class. When you
execute this program, yyy.abc() will call the abc function in class yyy and WriteLine will display
'abc'. Thereafter, both abc() and zzz.abc() will call the abc function in class zzz. And in each case
WriteLine will display 'abc in zzz'. Thus if you do not preface the function name with the name
of the class, C# will add the name of the class in which you are calling the function. In our case it
is zzz.
2
Namespaces
Normally, students have an implicit trust in their teachers. For they know that if the blind lead
the blind, both shall fall into the ditch. However, our philosophy is that a good teacher has to be
an even better liar!!
In accordance with this belief, initially we told you that WriteLine is the name of a function.
Then we told you that the name is not WriteLine, it is System.Console.WriteLine. But even that's
not true.
Console is actually the name of a class. Yes, trust us! There is no crying wolf here. The class
Console has a function called WriteLine. Hence the name now becomes Console.WriteLine.
However, that leaves out the word System. Now what does System mean?
Well, a number of functions like WriteLine are available in C#. Some functions will let you print,
some will enable writing of data to disk and others will let you create graphics. The problem that
we are posed with is - how does one remember which function satisfies what purpose?
Wouldn't it make sense if we logically grouped similar functions together? So, Microsoft thought
that all functions that can write to the screen could be made part of one class. All functions that
let you work with pictures could be part of another class. But even then, you will have too many
functions in one class. So they thought of having a single higher logical group. Such that all the
functions that have anything to do with the screen, i.e. whether you are drawing pictures or
writing text, be grouped once again into a higher body. Thus all classes that deal with interacting
with a database could go into a group called Data.
The second problem that we are posed with is that of name clashes. What do we mean by that?
Now, nothing can stop me from creating my own class called Console and include a function
called WriteLine in it. But how will C# know which Console am I referring to? The one that we
created ourselves, or the one that Microsoft has already created. In order to resolve these
problems Microsoft decided to take classes and put them into namespaces. What is a namespace?
It is simply a word. Thus we can logically group everything as per namespaces.
From the above explanation you would have by now guessed that System is nothing but a
namespace. The following programs will help make this concept crystal clear.
a.cs
class zzz
yyy.abc();
abc();
zzz.abc();
namespace vijay
class yyy
System.Console.WriteLine("abc");
}
}
Compiler Error
a.cs(5,1): error CS0246: The type or namespace name 'yyy' could not be found (are you missing
a using directive or an assembly reference?)
In the above program, the only change that we have made is that we have now included the class
yyy in a namespace called vijay. On doing so you will realize that the same program that worked
earlier doesn't work anymore. This is because yyy is put in a namespace vijay.
A namespace is nothing but a word with an open and close brace. The entire class is enclosed
within the namespace. If you want to access a function belonging to class yyy from another class
then the only way to do so is by saying vijay.yyy.abc(); Thus you specify the namespace first,
then the name of the class followed by the name of the function, each of them separated by dots.
Thus like Urdu, we read anything from the right and not the left. We start with the name of a
function, then the name of the class and whatever is left is the namespace.
Here zzz has not been given a namespace. If you don't specify a namespace then by default the
class is included in a global namespace. Now change yyy.abc(); to vijay.yyy.abc() and watch the
error disappear.
a.cs
class zzz
vijay.yyy.abc();
abc();
zzz.abc();
{
System.Console.WriteLine("abc in zzz ");
namespace vijay
class yyy
System.Console.WriteLine("abc");
Output
abc
abc in zzz
abc in zzz
We bet your faces are now beaming! Seems like the secret of happiness is not in doing what one
likes to do but in liking what one has to do. We had to get rid of the error which we have
succeeded in doing. The error has disappeared; the program executes as advertised and it
generates the same output as it did previously.
Thus all the classes and functions created by Vijay can be included in a namespace called vijay.
If Sonal creates a namespace by her name then she can include all the functions and classes
created by her in the namespace sonal. Thus there will be no name clashes at all. These
namespaces that are created by us are called user-defined namespaces whereas System is a pre-
defined namespace. Thus System is a namespace in which a class called Console was created,
which contained a function called WriteLine.
Thus the namespace concept allows us to create logical groups. So all xml related classes can be
in a namespace called xml, web can be in a web namespace and so on and so forth.
But the only problem now is that when you start writing code you have to specify the namespace
first, then the class name followed by the function name. Well, everything is available but for a
price! Our consolation is that it is a very small price to pay.
a.cs
namespace mukhi
class zzz
vijay.yyy.abc();
abc();
zzz.abc();
mukhi.zzz.abc();
namespace vijay
{
class yyy
System.Console.WriteLine("abc");
Output
abc
abc in zzz
abc in zzz
abc in zzz
In the above program, we have two classes zzz and yyy. The class zzz is included in a namespace
called mukhi and the class yyy is included in a namespace called vijay.
So when we say abc(); in Main, Main is in zzz, so you are actually writing mukhi.zzz.abc(); This
is because C# will automatically expand it since the function abc is available within the same
class. Hence it is at your discretion as to how you want to write it. You can say abc(), zzz.abc() or
mukhi.zzz.abc(); finally they all expand to namespace.classname.function name. C# adds the
name of the namespace and the name of the class even if you do not specifically write it. The
concept of namespaces is not very difficult to understand. It allows for a hierarchical grouping of
classes. It tells us which classes are logically grouped. It also avoids classes from having the
same name.
a.cs
class zzz
Compiler Error
a.cs(5,1): error CS0246: The type or namespace name 'Console' could not be found (are you
missing a using directive or an assembly reference?)
If we do not enclose our class in a namespace, it becomes part and parcel of the global
namespace ‘ ‘. This namespace does not contain a class called Console. We had mentioned
earlier that the class Console is contained in the namespace System. We do not want to preface
the Console class with the namespace System each and every time. The only reason being that
our fingers will wear out typing the word System over and over again. So C# lets us use a
shorthand by means of which we avoid the pain of having to keep on writing the name of a
namespace over and over again.
a.cs
using System;
class zzz
Output
abc in zzz
The secret here is not in doing great things, but doing a small thing in a great way. We get no
error simply by employing the word using which is part of the C# language. All that using does
is whenever it sees only the name of a class, it goes and adds (in this case) the word System.
Thus we do not have to write the word System over and over again. This works the way
shorthand does.
a.cs
using System;
class zzz
yyy.abc();
namespace vijay
class yyy
Console.WriteLine("abc");
Compiler Error
a.cs(6,1): error CS0246: The type or namespace name 'yyy' could not be found (are you missing
a using directive or an assembly reference?)
Now we get an error for yyy and not for Console as the yyy class belongs to the vijay namespace
and not the global namespace. Because of the using keyword, C# adds the namespace System to
yyy yielding System.yyy.abc and realizes that System does not contain a class called yyy. Hence
the error.
a.cs
using System;
using vijay;
class zzz {
yyy.abc();
namespace vijay
class yyy
Console.WriteLine("abc");
Output
abc
The error vanishes as C# first tries System.yyy.abc gets an error, then tries vijay.yyy.abc and is
successful. Thus by having two using's we do not have to write the namespaces vijay or System
ever again.
a.cs
using System;
using mukhi;
using vijay;
namespace mukhi
class zzz
yyy.abc();
abc();
zzz.abc();
zzz.abc();
}
namespace vijay
class yyy
System.Console.WriteLine("abc");
Output
abc
abc in zzz
abc in zzz
abc in zzz
We can have as many using's as we like and the compiler will try each one in turn. If none of
them match we will receive an error. In this case it will try 3 times with System, mukhi and vijay
and if none match, you will get an error.
a.cs
using System.Console;
class zzz
{
WriteLine("abc in zzz ");
Compiler Error
a.cs(1,7): error CS0138: A using namespace directive can only be applied to namespaces;
'System.Console' is a class not a namespace
After the word using you can only write the name of a namespace. System.Console is a
namespace class combination which is not allowed.
Building Hierarchy
In C# you organize classes using namespaces. Now let's discover the extent we can go to as far
as organizing classes.
a.cs
class zzz
mukhi.vijay.yyy.abc();
namespace mukhi
namespace vijay
class yyy {
System.Console.WriteLine("abc");
Output
abc
In this program we have a namespace within a namespace i.e. within the namespace mukhi we
have another namespace vijay. Thus namespaces are 'hierarchical'. If you want to access the
function abc in yyy you have to specify it in the form- namespace.classname.functionname. So,
the qualified name is now mukhi.vijay.yyy.abc(); Once the function is called, WriteLine will
display 'abc'.
In order to differentiate between the various names separated by dots, always read backwards.
Reading backwards, the first is the function name then the class name and the names thereafter
will all be namespaces.
Alternatively, you can directly specify the namespace as mukhi.vijay, as we have done below.
This program generates the same output as previously, it prints abc.
a.cs
class zzz
mukhi.vijay.yyy.abc();
namespace mukhi.vijay
{
class yyy
System.Console.WriteLine("abc");
Output
abc
Here we have a single namespace by the name mukhi.vijay. The name mukhi.vijay is actually a
shortcut for defining a namespace named mukhi that contains a namespace named vijay. In this
program, we have only two namespaces. But you can expand it further to include a number of
namespaces depending upon the level of hierarchy required by your program.
We can liken this to an organization. Let's consider mukhi to be the name of the company. Within
that you have a sub-company or a division called vijay, which creates it own classes. As such the
level of hierarchy can be expanded.
Before you understand the next program let's address a simple question. Why do you use classes?
Classes are used because they offer a large number of functions. You don't use classes because of
the variables that you can create within them; you use classes for the functions that they provide.
Remember, you call a function using the form -namespace.classname.functionname.
File Operations
a.cs
class zzz
File.Copy("c:\\csharp\\a.txt","c:\\csharp\\b.txt",true);
Compiler Error
a.cs(5,1): error CS0246: The type or namespace name 'File' could not be found (are you missing
a using directive or an assembly reference?)
Our next program will enlighten you on something most sought after - The art of Copying. Ah!
Finally something of interest!
This program introduces the 'Copy' function. It allows you to duplicate a file. File is a class and it
has a function called Copy, which is static.
The first parameter 'a.txt' is the source file i.e. the file, which we want to duplicate. The second
parameter 'b.txt' is the destination file i.e. the file that we want to copy to. Note that you must
specify the entire path for the file name. The last parameter 'true' implies that if the file exists
then it will be overwritten. If the file does not exist it will be created and contents of the source
file will be copied onto it.
And just when you thought you had mastered the art of copying the program returns with an
error message. The error says C# does not know what File.Copy is. The problem is that the name
of the namespace is System.IO. So you have to specify the namespace too.
a.cs
class zzz
System.IO.File.Copy("c:\\csharp\\a.txt","c:\\csharp\\b.txt",true);
}
The program does not generate any compilation errors. Create a file called a.txt with some text
before you run this program. Execute this program and then open the file 'b.txt'. Finally, the task
has been accomplished! You now have the contents of a.txt copied into b.txt.
a.cs
class zzz
System.IO.File.Delete("c:\\csharp\\a.txt");
The above program takes the name of a file as the parameter. This function will remove the file
specified from disk. Give the dir command at the command prompt and you will find that the file
has been deleted.
Every language will offer you millions of such functions like copy and delete. These functions
were always available, but C# has gone one step further and made these functions a part of a
Class. They are now part of a Namespace. Hence it becomes easier to categorize functions. It is
but a question of detail whether you should or should not categorize them.
3
Constructors and Destructors
New
a.cs
class zzz
yyy.abc();
class yyy
System.Console.WriteLine("abc");
}
Compiler Error
a.cs(5,1) : error CS0120: An object reference is required for the nonstatic field, method or
property 'yyy.abc()'
This program contains one class called yyy which has a function called abc. In Main() we are
using the syntax yyy.abc() to call the abc function as we did earlier. Within the abc function we
have the code for the function abc that will print the string "abc". On compiling this program you
will get an error as incomprehensible as ever!
But how is it that when we ran this program earlier we didn't get an error? If you are still
bewildered, wake up and smell the coffee! Didn't you notice we removed the word 'static' while
saying public void abc(). Hence we get an error.
In our earlier programs when we wrote the function abc we had written the word static which is
missing now.
No, we are not going to tell you to add the word static and execute the program. We are not that
predictable! On the contrary, we shall do something quite different and interesting. Keeping that
in mind let's consider the next program.
a.cs
class zzz
yyy a;
a.abc();
class yyy
{
System.Console.WriteLine("abc");
Compiler Error
Before we look into this program let's get our basics clear. We have often used the statement 'int
i' meaning that i was a variable that looked like an int. When we used the statement 'string s', it
meant that s was a variable that looked like string. Similarly, in this program we are saying yyy
a. This implies that 'a' looks like yyy. What is yyy? It is the name of a class. Here we do not call
'a' a variable, we call it an object. An object and a variable can be used interchangeably.
Earlier, whenever we wanted to call a member from a class we would say yyy.abc(); i.e. class
name dot function name. But in our current program we are saying a.abc(); We are using the
same dot, but now it gives an error saying - 'Use of unassigned local variable'. Note that the word
member is analogous with the word function.
But things still don't seem any clearer. So, let's go a step further and add another statement
a=new yyy(); Match your code with the one below.
a.cs
class zzz
yyy a;
a=new yyy();
a.abc();
class yyy
{
System.Console.WriteLine("abc");
Output
abc
The word or keyword new must be followed by the name of a class; You cannot substitute it with
anything else, it must be a class. In our case, we have given the statement as new yyy(). yyy is
the name of an existing class. But why have round brackets after the class name? The '(' and ')'
brackets are part of the syntax. And you very well know by now that you can't argue with syntax.
Thus it is at this point i.e. after saying new, that the object 'a' that looks like yyy is created. We
could have also called the object 'a' an instance of the class yyy. Since the class yyy has only one
function it will allocate memory for THAT one function ONLY. Now we have an object 'a' that
looks like class yyy. Once the object is created, it can be used to access the function from class
yyy. Hence, now if we say a.abc() we will not get an error.
Thus an object is nothing but an instance or an occurrence of a class. Therefore, 'a' is an instance
of the class yyy. This is how you can instantiate an object.
In order to create an object you must use the keyword 'new'. Our next program will help you gain
a better understanding of this concept.
a.cs
class zzz
int i;
i=new int();
}
At first we have int i, meaning i looks like int. Then we have i=new int(); Executing this program
will not generate any errors. But so far whenever we used int i we never created the object i
using new int(). This is because C# does this internally for us. It saves us the trouble of doing so.
Then why doesn't C# do so for all the other objects that we create? This is because C# recognizes
only two types of classes.
The first type is one that the C# compiler knows of in advance. int, long, bool, and string are
classes that fall into this category. These are predefined classes. But we call them data types
because in C and C++ they were called data types and C# has a legacy of C and C++. So
technically, when we say int i it does i=new int(); internally.
The second type of classes that C# recognizes are the ones that we create i.e. user-defined
classes. For user-defined classes we have to create objects ourselves. Thus anything other than
the basic data-types must be explicitly created.
So when we say 'yyy a' we are not creating the object at this point. We are only declaring the
object to be of type yyy. It is only when we use the word 'new' that the object is created and
memory is allocated for the same. Therefore, when we have our own classes, that's the time we
use new. Without new you cannot create an object.
Static
You are certainly going to benefit by the patience you have shown so far. To find out how, let's
follow the next program.
a.cs
class zzz
yyy a;
a=new yyy();
a.abc();
yyy.pqr();
}
class yyy
System.Console.WriteLine("abc");
System.Console.WriteLine("pqr");
Output
abc
pqr
In this program we have two functions abc and pqr. It is of significance to note that the function
pqr has the word static whereas abc does not. If you want to access the static function pqr you
say yyy.pqr() and to access the non static function abc you say a.abc(); You can't do the reverse
i.e. you cant say a.pqr() and yyy.abc().
a.cs
class zzz
{
yyy a;
a=new yyy();
yyy.abc();
a.pqr();
class yyy
System.Console.WriteLine("abc");
System.Console.WriteLine("pqr");
Compiler Error
a.cs(7,1): error CS0120: An object reference is required for the nonstatic field, method, or
property 'yyy.abc()'
a.cs(8,1): error CS0176: Static member 'yyy.pqr()' cannot be accessed with an instance reference;
qualify it with a type name instead
The word 'static' implies 'free'. Static signifies that you can access a member or a function
without creating an object. At last you are enjoying the fruits of patience!
Observe that the function Main in zzz is static. This is because we are not creating any object that
looks like zzz. The crux is that if you don't want to use 'new' and yet use the function then you
must make the function static.
In both cases a dot is used to reference the function. The only difference is that a static member
belongs to the class and as such we don't need to create an object to access it. On the other hand,
a non-static member, that is the default, can be accessed only via an object of the class. Thus
WriteLine is a static function in Console as we did not create an object that looks like Console to
access it.
a.cs
class zzz
System.Console.WriteLine(yyy.i);
class yyy
Compiler Error
a.cs(5,26): error CS0120: An object reference is required for the nonstatic field, method, or
property 'yyy.i'
Why did we get an error? Think for thinking is the hardest work there is, which is probably the
reason why so few engage in it. If you still haven't got it, let us enlighten you. The same rules for
static apply to functions as well as variables. Hence we get the above error.
a.cs
class zzz
{
a.j = 11;
System.Console.WriteLine(a.j);
System.Console.WriteLine(b.j);
yyy.i = 30;
System.Console.WriteLine(yyy.i);
class yyy
Output
11
10
30
A static variable belongs to the class. Hence if we create a static variable i, no matter how many
objects we create that look like yyy, there will be one and only one value of i as there is only one
variable i created in memory. Thus we access a static variable by prefacing with the name of the
class and not name of object. If the variable is non-static like j then we have to use the syntax as
explained earlier i.e. name of object dot name of variable. Thus each time we create an object
that looks like yyy we are creating a new/another copy of the variable j in memory. We now have
two j's in memory one for a and another for b. Thus j is called an instance variable unlike i.
When we change the variable j of a to 11, the j of b remain at 10.
Thus functions are created in memory only once, irrespective of the word static. If a class has no
instance or non static variables then it makes no sense to create multiple instances of the object
as there will be no way of distinguishing between the copies created.
Constructors
a.cs
class zzz
yyy a;
System.Console.WriteLine("Main");
a=new yyy();
class yyy
public yyy()
System.Console.WriteLine("yyy");
Output
Main
yyy
In the above program we have a class called yyy. We also have a function called yyy which
happens to be having the same name as the name of the class. We have a friend named Bunty.
Coincidentally, the name of his pet dog is also Bunty! Similarly, it is absolutely legal to have a
function by the same name as that of the class. In this case first we see Main and then we see yyy
displayed on the screen which means that the function yyy() gets called automatically. Note, we
have not called the function yyy explicitly.
Initially we are saying yyy a. By doing so we are specifying that 'a' looks like yyy. We are not
creating an object that looks like yyy. The next statement has System.Console.WriteLine, which
will print 'Main'. Thereafter, using new we are creating an object a. It is at this point that C# calls
the constructor i.e. it calls the function yyy(). Now you will see 'yyy' displayed. This goes to
prove that as soon as an object of a class is created, C# automatically calls the constructor. A
constructor gets called at the time of birth or creation of the object. It has to have the same name
as the name of the class.
a.cs
class zzz
yyy a;
System.Console.WriteLine("Main");
a=new yyy();
a.yyy();
class yyy
{
public yyy()
System.Console.WriteLine("yyy");
Compiler Error
a.cs(8,1): error CS0117: 'yyy' does not contain a definition for 'yyy'
Here, we are calling the function yyy using the appropriate syntax i.e. by saying a.yyy(). Now,
run the compiler. Baffled by the error? The error says 'yyy' does not contain a definition for
'yyy'. The class yyy does contain a function called yyy which got called in the previous example.
Has C# developed amnesia all of a sudden? What went wrong? Well, you cannot call this
function using a.yyy() or yyy.yyy() The catch is that when you have a function with the same
name as that of the class you cannot call it at all. It gets called automatically. C# does not give
anyone the authority to call such a function. It calls this function automatically only at birth.
Seems abnormal doesn't it!
A constructor can be used in cases where every time an object gets created and you want some
code to be automatically executed. The code that you want executed must be put in the
constructor. That code could be anything, it could check for hard disk space, it could create a file
or it could connect to the net and bring a file over. What that code will do shall vary from person
to person.
To understand how and when the constructor gets called, let's take into consideration our next
example. Now remove the word 'public' in front of yyy() as we have done below.
a.cs
class zzz
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
class yyy
yyy()
System.Console.WriteLine("yyy const");
Compiler Error
Obviously, you will get an error. This is because without the word public the function is private
property. And when you trespass on private property you have to face the consequences. In our
case we are faced with an error. By making the function public every one can use it, it is now
becomes public property! If the constructor is private then nobody can create an object that looks
like yyy.
Do you think constructors can return values? Let's try it out and find out for ourselves.
a.cs
class zzz
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
class yyy
System.Console.WriteLine("yyy const");
Compiler Error
a.cs(12,12): error CS0542: 'yyy': member names cannot be the same as their enclosing type
Executing the above program generates an error. It says that member i.e yyy cannot be the same
as the enclosing type i.e class yyy. Now, that is an error that you certainly didn't expect.
Here we are saying public int yyy implying that the function yyy() is returning an int. yyy() is a
constructor and is called automatically at the time an object is created. If a constructor is to
return a value then to whom should it return the value to? Since it is called automatically, there is
nothing that can accept the return value. Thus constructors cannot return values. Also when a
constructor gets called, an object is in the act of being created. It has not yet been created. The
keyword new first allocates memory for the functions and the variables. After this it calls the
constructor. When the constructor finishes, then we say that the object has been created. Thus the
constructor has no one to return values to.
Now that we know constructors don't return values let's return void instead.
a.cs
class zzz
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
class yyy
System.Console.WriteLine("yyy const");
Compiler Error
a.cs(12,13): error CS0542: 'yyy': member names cannot be the same as their enclosing type
Though we are returning void, we get the same error. This is because C# is very sure of what it
says. When you borrow from other people you do so on the pretext that you will return it. It's a
different story that you never do! You rarely mean what you say. But when C# says that
constructors cannot return values it means 'constructors cannot return values', not even 'void'.
Remember, there is nothing that can accept the return values. Hence even void cannot be
accepted. When a function returns a void we mean that it will return no value at all. For a
constructor, the word return makes no sense at all.
Just as we pass parameters to other functions, you can also pass parameters to constructors.
a.cs
class zzz
yyy a;
System.Console.WriteLine("hi");
a=new yyy("no");
class yyy
public yyy()
System.Console.WriteLine("yyy const");
Compiler Error
a.cs(7,3): error CS1501: No overload for method 'yyy' takes '1' arguments
You are already aware of the fact that parameters are passed to functions while calling them.
Similarly, we will pass a parameter to the constructor yyy while creating the object a; because it
is at this point that the constructor gets called.
Hence we are saying a=new yyy("no"). But on compiling this program you get an error. Here,
the constructor is being called with a string 'no' as a parameter. But there is no variable in the
constructor yyy to store the value 'no'. Add 'string s' in the constructor yyy and watch the error
disappear.
a.cs
class zzz
yyy a;
System.Console.WriteLine("hi");
a=new yyy("no");
class yyy
public yyy(string s)
System.Console.WriteLine(s);
Output
hi
no
At first WriteLine will display 'hi'. Then we have a constructor yyy that takes a string 'no' as a
parameter and accepts it in a variable s. Thus the moment the constructor yyy is called 'no' will
be displayed. This is because the constructor yyy contains code that will print the value stored in
the variable s. This is how constructors with parameters are called.
So far we created only one instance of the class yyy. In the following program we are creating
two instances of the class yyy, 'a' and 'b'.
a.cs
class zzz
yyy a,b;
System.Console.WriteLine("hi");
a=new yyy("no");
b=new yyy();
class yyy
public yyy(string s)
System.Console.WriteLine(s);
Compiler Error
a.cs(8,3): error CS1501: No overload for method 'yyy' takes '0' arguments
While creating the object 'a' the constructor yyy is being passed a parameter 'hi'. In case of the
object 'b' the constructor will be called without any parameters. But in our program we have code
only for the constructor with parameters. Try executing this program and you will get an error
saying that method yyy takes 0 arguments. This is because we do not have code for the
constructor without parameters.
In our earlier programs, we did not specify a constructor. A relevant question here would be -
how did the objects get created then, without the constructor being called? C# is a Good
Samaritan, at that time it inserted a free constructor. It does so internally. On its own it inserts a
constructor without any parameters, without any code into the class.
yyy()
Point to ponder - in the above program, when we didn't create a constructor without parameters
why didn't we get one free? Remember we said C# is a Good Samaritan? And Good Samaritans
help the needy. On seeing that we already have a constructor with parameters, C# looks the other
way i.e., it takes the free one away. However, it is only when you have no constructor at all that
C# melts its heart and gives you one free. Remember, even if it finds that you have even one
constructor it will take away the free one. On the assumption that if you can provide one
constructor, then with a little effort you can work towards providing the others too!
Now the only way to get rid of the error is to add the constructor yourself.
a.cs
class zzz
yyy a,b;
System.Console.WriteLine("hi");
a=new yyy("no");
b=new yyy();
class yyy
public yyy(string s)
System.Console.WriteLine(s);
public yyy()
System.Console.WriteLine("bad");
Output
hi
no
bad
Here, initially, the two objects 'a' and 'b' are declared. In the next statement we have WriteLine,
which will display 'hi'. We are then creating the object a. At this point the constructor with a
string as a parameter is called. It will now display the value stored in the variable s which is 'no'.
Thereafter, the object b is created. At this point the constructor without the parameters will be
called. This constructor contains the WriteLine statement, which will print 'bad'. Here, we have
as many constructors as we are calling and hence we do not get any errors.
So, essentially, a constructor is a special function that gets called when an object is created. It
does not return any values, not even void. As far as parameters go it behaves like a normal
function. If no constructors are specified you get one free, otherwise, you need as many
constructors as you are calling. Hence in the above case we cannot create an object as new
yyy(100) as we do not have a constructor that accepts one int as a parameter.
Destructors
a.cs
aa a = new aa();
public class aa
public aa()
System.Console.WriteLine("Constructor ");
~aa()
System.Console.WriteLine("Destructor");
Output
Constructor
Destructor
A destructor is a function with the same name as the name of a class but starting with the
character ~. A constructor gets called at birth whereas a destructor gets called at death. In C#
unlike other languages we do not know when an object dies as unlike James Bond, we do not
have a license to kill. Thus even though the object a dies at the end of main, the destructor may
not get called. Thus, in C# we cannot decide when the destructor gets called. This decision to call
the destructor is made by a program within C# called the garbage collector.
The concept first gained currency with the advent of Java. In Java and C# we cannot remove our
objects from memory. Thus it is for the garbage collector to decide when to call the destructor.
The programming world was replete with errors mainly because programmers use new to
allocate memory and then forget to deallocate it. This gave rise to a concept called memory
leaks. On the flip side of the coin, programmers deallocated the memory, forgot about it and then
accessed the object again. This generates an error occurring at random and difficult to pin down.
a.cs
aa a = new aa();
public class aa
public aa()
System.Console.WriteLine("Constructor");
public ~aa()
{
System.Console.WriteLine("Destructor");
Compiler Error
a.cs(14,9): error CS0106: The modifier 'public' is not valid for this item
a.cs
aa a = new aa();
public class aa
public aa()
System.Console.WriteLine("Constructor");
~aa(int i)
{
System.Console.WriteLine("Destructor");
Compiler Error
a.cs(16,25): error CS1519: Invalid token '(' in class, struct, or interface member declaration
Constructors come in plenty with different numbers of arguments being passed to them.
However, in the case of destructors, one size fits all, i.e., they come in only one size, with no
parameters. Here we created a destructor with an int as a parameter thereby confusing the C#
compiler completely.
C# lacks true synchronous or deterministic destructors i.e. destructors being called at a certain
point in time. You cannot have your life depend on when a destructor would be called. The
common grouse against C# is that unlike C++ it does not support true destructors.
a.cs
aa a = new aa();
public class aa
public aa()
{
System.Console.WriteLine("Constructor");
~aa()
System.Console.WriteLine("Destructor");
Compiler Error
a.cs(18,25): error CS0111: Class 'aa' already defines a member called 'Finalize' with the same
parameter types
We tried to create a function called Finalize. The compiler comes back and tells us that we
already have a function called Finalize. This is weird as we have only one Finalize function. The
reason for this error is that the compiler converts our destructor from ~aa to Finalize.
Arrays
All programming languages embrace the concept of arrays. An array is nothing but more of one
entity i.e., a multiple of the same type. Simply put, when we have five books, we don't just say
we have five books. Instead we say we have an array of five books. So, whenever you want to
store multiple values of variables you store them in an array.
a.cs
class zzz
int[] a;
a= new int[3];
System.Console.WriteLine(a[0]);
a[0]++;
System.Console.WriteLine(a[0]);
int i;
i=1;
System.Console.WriteLine(a[i]);
i=2;
System.Console.WriteLine(a[i]);
Output
10
20
Here 'a' is an array of ints. You declare arrays with a set of [] brackets. At this point it is not
known how large the array will be. For that we have a=new int[3]; after new we have int
meaning we want to create a variable of type int. We are putting 3 in the square brackets meaning
we want to store 3 ints. This will create three ints a[0], a[1] and a[2]. They are then initialized to
the values 1,10 and 20 respectively. To initialize an array variable we use the name, i.e. in this
case a and follow it with the open and close [] brackets. Inside them we put the array number.
The first variable is called a[0] , the second a[1] and so on. C# like most computer programming
languages likes to start counting from 0 and not 1. Therefore, the last variable is a[2] and not
a[3].
Since an array is many of the same type, they all have the same name. In our earlier example,
even if we have many books, all the books will be called books. However, to refer to them
individually you can say book1, book2, book3 etc.
WriteLine will display the value stored in a[0] which is 1. a[0]++ will increment the value stored
in a[0] by one. WriteLine will now display 2.
Thereafter, the variable i is declared as an int. It is then initialized to 1. Within the WriteLine
function we have a[i]. It is not specifically stated which variable, instead we have said a[i]. There
is no variable called a[i], but i has a value 1, so it is read as a[1]. Hence the value stored at a[1],
which is 10, is displayed. The next WriteLine will display the value stored in a[2] as i is
reinitialized to 2.
Doing this makes our program more generic. We haven't specifically stated which variable, we
are letting a variable called i decide the name of the variable.
The next example demonstrates how arrays can be used within loops.
a.cs
class zzz
int[] a;
a= new int[3];
int i;
a[i]= i*10;
System.Console.WriteLine(a[i]);
}
}
Output
10
20
The advantage of using arrays is that you can decide the name of the variable later and they can
also be used in loops.
Here 'a' is an array of ints and i is a variable of type int. The array size is 3 i.e. it can store three
ints. The first for loop is used to initialize the individual array items. Within the for loop, i is
initialized to 0. The condition i<=2 indicates that the loop will execute thrice. So, when the
control enters the for loop, for the first time i is 0. Looking at the right hand side of the
expression, i*10 will now read as 0*10, which is 0. Hence, a[i] which is read as a[0] will be
initialized to 0. i++ increments the value of i to 1. The second time a[i] will be read as a[1] which
will be initialized to 10. Thereafter, a[i] will be read as a[2] and initialized to 20 as i is now 2.
Now i will be 3, so the condition evaluates to false and the loop terminates.
The second for loop displays the values stored in the array. This is similar to the above loop.
Here we are displaying the values of the individual array items. As the for loop executes,
WriteLine will read a[i] as a[0], a[1] and a[2] in each case. As such, WriteLine displays 0,10,20.
So, starting from the beginning and going upto the end, all the values stored in the array are
displayed.
Arrays can also be used in a foreach statement. This is exemplified in the following program.
a.cs
class zzz
int[] a;
a= new int[3];
System.Console.WriteLine(i);
Output
10
20
The foreach statement lists the elements of the array. It executes a statement for each element of
the array or collection. 'a' is an array of type int that can store three items. a[0], a[1] and a[2] are
the elements or items of the array. They have been initialized to 1, 10 and 20 respectively. In the
foreach statement we have ( int i in a ).
i is a variable of type int and a is the array created earlier. The first element of the array 'a' is a[0]
and it holds the value 1. The foreach statement picks up this value and stores it in i. Since i now
holds the value 1, WriteLine displays 1. The second element is a[1]. It picks up its value, which
is 10 and stores it in i. Thus i now holds the value 10. WriteLine will now display 10. This goes
on for all the elements of the array. Our array 'a' comprises three elements. Hence the foreach
will execute the WriteLine statement for each of them and display their values 1,10 and 20. The
variable i is only available in the foreach. The foreach makes it easier for us to run through all
the members of any array.
Variables are the cornerstone of programming languages. In a way, they are like items contained
in a bag. You can put an item in a bag, remove it therefrom, or replace it with another. Our next
few programs shall be explained along these lines.
a.cs
class zzz
{
int i=100;
yyy a;
a=new yyy();
a.abc(i);
System.Console.WriteLine(i);
class yyy
System.Console.WriteLine(i);
i=10;
Output
100
100
'a' is an object that looks yyy. The variable 'i' is initialized to a value 100. Then the object 'a' that
looks like yyy is created. We are now calling the function abc with one parameter 'i'. Within the
abc function we are printing the value of i. When we call the function abc from Main, i had a
value 100. So the variable i in abc also has a value 100. Thus WriteLine will display the value
100. We are now assigning i a new value 10. But the i that changes is the parameter i in abc, and
not the i of Main in zzz. It's like having two similar bags, where you change the contents of only
one. So the WriteLine in Main will again print 100.
Thus the variable i within the abc function is temporary. It exists only within the '{' and '}' braces
of the function. Therefore, this 'i' is local to the function. Its value is not available in Main. It's
like your memory, temporary. It exists as long as you are reading this book. Once the book is
over everything is forgotten! Thus please do not call the variable i in abc as i because it will
confuse everyone. Thus i in abc has nothing to do with the i in Main. Ergo, changing i in abc will
have no effect on the i in Main.
But a situation could arise wherein you would like the function abc to change the value of i. In
this context you are saying, I am giving a variable to a function abc, use it, but I would also like
the function abc to change it. And once its value is changed in the function, it i.e. the changed
value should be available in Main. Let's see how we can handle a situation like that.
a.cs
class zzz
yyy a;
int i=100;
a=new yyy();
a.abc(i);
System.Console.WriteLine(i);
class yyy
i=10;
}
}
Compiler Error
a.cs(8,1): error CS1502: The best overloaded method match for 'yyy.abc(out int)' has some
invalid arguments.
a.cs(8,7): error CS1503: Argument '1':cannot convert from 'int' to 'out int'.
This program is exactly like the previous one. The only change is that we added the word 'out' in
the function abc along with the parameter i. We get an error on compiling this program. You
realize, we are saying a.abc(i) in Main, but in the function we are saying abc(out int i). 'out' is the
key to solving our previous problem. 'out' means whatever changes you will make in abc, they
will be visible outside the function also.
Note that it doesn't matter what you call the variable in the function abc, the original will change.
So, instead of saying abc(out int i) you could have used another variable. In that case, if you said
abc(out int p) it would be absolutely legal. To do away with the error you must specify 'out' while
calling the function as well.
a.cs
class zzz
yyy a;
int i=100;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
}
class yyy {
i=10;
Output
10
In this program, we now have 'out' in both cases: in the function call and the function itself. So
by saying a.abc( out i) you are implying that you are allowing the function abc to change the
value of i. Then in the function definition we also have the word 'out', so it knows i is going to
change and hence i now changes in the original. Therefore, WriteLine will displays the new
value 10.
We are now using the word 'ref' instead of 'out'. Let us see the effects of doing so.
a.cs
class zzz
yyy a;
int i=100;
a=new yyy();
a.abc(ref i);
System.Console.WriteLine(i);
}
}
class yyy
j=10;
Output
10
This program executes smoothly and gives the same output as previously. It displays the value
10. So in that sense 'ref' is like 'out'. In either case the original value of 'i' changes. Thus, if you
are calling the function with 'ref' then state 'ref' in the function also. If you are calling the
function with 'out' then give 'out' in the function also.
Game for some experimentation? Let's try to execute the above program without initializing the
variable i.
a.cs
class zzz
yyy a;
int i;
a=new yyy();
a.abc(ref i);
System.Console.WriteLine(i);
class yyy
j=10;
Compiler Error
Here we are saying int i. Note that we are not initializing i. We are using 'ref' which gives us an
error. The error says 'use of possibly unassigned local variable i'. Here we didn't initialize i and
yet we are trying to use it; hence we get an error.
Now, let's look at the next example. Here we have the same program only now we are using 'out'
instead of ref.
a.cs
class zzz
yyy a;
int i;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
class yyy
j=10;
Output
10
In this program we haven't initialized i either but this time we don't get any error. This goes to
show that when using 'ref' the variable must be initialized and only then can you change its
value. In case of 'out' you don't have to initialize the variable to change its value.
But why have this differentiation? This is because in case of 'ref' you can read the value of the
variable as well as write to it. Therefore, if one has to read the value of the variable, it must be
initialized before hand. But it is your discretion whether you want to change the value, read it or
do both.
But in case of 'out' you can only write i.e., you can only change the value of the variable, you
cannot read it. So, in case of 'out' since it does not read the variable it doesn't matter even if it is
not initialized.
This is further exemplified with the help of the next few programs. In the following program we
have initialized i. Note here we are using 'out'.
a.cs
class zzz
{
yyy a;
int i=10;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
class yyy
System.Console.WriteLine(j);
j=10;
Compiler Error
Within the function abc we are first printing the value of i using the WriteLine statement. That
means we are trying to read the value of i which is passed to the variable j in the function abc.
But with 'out' one cannot read values hence we get an error. Now if you try the same program
with 'ref' instead of 'out' you will not get any errors. This is because with 'ref' you can read the
values as well as well as change them.
However do note that all 'out' parameters must be initialized or else you will get an error form
the compiler as follows.
a.cs
class zzz
yyy a;
int i=10;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
class yyy
Compiler Error
a.cs(14,13): error CS0177: The out parameter 'j' must be assigned to before control leaves the
current method
So where can we use 'out'? We can use 'out' if we want the function to make some calculations
and fill up the variable.
a.cs
class zzz
yyy a;
int i=10;
a=new yyy();
a.abc( out i );
System.Console.WriteLine(i);
class yyy
i= 20 * 20;
Output
400
In this program we are using 'out'. We are multiplying 20 by 20 and storing the result 400 in i.
Thereby the value of i is changed and WriteLine will now print 400.
class zzz
yyy a;
int i=10;
int k=20;
int m;
a=new yyy();
System.Console.WriteLine(i);
System.Console.WriteLine(k);
System.Console.WriteLine(m);
class yyy
int j;
x=30;y=10;
j=x * y;
return j;
Output
30
10
300
After specifying that a looks like yyy, the two variables i and k are initialized to the values 10
and 20 respectively. Then the object a is created. The third variable m is of type int and is used to
store the return value of the function abc. By using 'out', the function abc is called with two
parameters, i and k. The abc function has the variables x and y. Within the function another
variable j is declared of type int. The variables x and y are assigned new values 30 and 10
respectively. Their values are multiplied and stored in j, i.e. 300. The next statement return j will
yield the value of j, which is stored in m. Now WriteLine will display the value of i as 30. This is
because with the abc function we filled up i with the value 30. Similarly, the next WriteLine
statement will print the value of k, which is 10. Then we print the value of m, which is 300.
In a nutshell-
A point to note is that when we say 'ref' it means we will initialize the variable. The abc function
expects the variable to be initialized so that the function can use the value of the variable. When
the variable changes the change is reflected outside. So, whenever you say 'ref' the variable has
to be initialized, otherwise an error occurs. The function will assume that the variable is
initialized because it expects to read the value. You may choose to read the value or change it or
do both.
But when you say 'out' it implies that we are not going to initialize the variable, that the abc
function is not going to use the value, it is only going to change the value. When there is an 'out',
abc can use the variable even if it is not initialized. This is because you cannot read the value in
case of an 'out' variable; the function can only change the value. In other words, it has to change
the value of the variable to avoid any errors.
4
Components and Database Handling
Exception Handling
Failing to prepare is preparing to fail. Ergo, one is constantly planning and preparing for the
future. We often set a path for ourselves and try to follow it steadily. But then life intervenes.
Uncertainties in life result in unforeseen situations. These are like exceptions in the normal
course that we set for ourselves. Similarly, when you write programs, unforeseen problems may
arise during its normal path of execution.
These unforeseen problems are nothing but an euphemism for errors. Just as in life, in the
programming world, these errors can be further classified into Fatal errors and Non-Fatal errors.
A Fatal error is an error that brings the program to a grinding halt. A Non-Fatal error is an error
that allows your program to run but with limited capacity. This can be exemplified by the
following.
Let's assume you have a card that is not of a high resolution. Accordingly, your browser displays
your page in a lower resolution. Now, technically, that is an error but it is not a Fatal one.
However, if you didn't have a graphics card at all then it would be a Fatal error. Thus, we may
also call an unforeseen problem or error an Exception. In other words, therefore, the word
Exception is used almost synonymously with the word Error.
Earlier, the problem was that we never centralized error handling. Let's assume you have to open
three files. Each time you open a file you have to check whether an error occurred or not. So you
have to conduct that check for every file. Since there are three files, it would mean repeating the
same error check thrice. That is surely a waste of time. Or you could be calling two functions and
checking for the same error in both the functions. One reason that programmers don't write error-
handling routines is that they get tired of the mundane task. It is the same thing repeated over and
over again.
Let's consider constructors. Before the constructor gets called, the object has not yet been
created. So you ask the constructor to create an object, to allocate memory and create a file.
Now, if it can't do so, how will the constructor return to tell you that an error occurred! Today
constructors carry a lot of code within them and if you haven't forgotten, constructors cannot
return values.
Because of the various reasons discussed above, we don't talk about errors any more; we handle
exceptions. Bearing this in mind let's understand the next program.
a.cs
class zzz
yyy a;
a=new yyy();
a.abc();
System.Console.WriteLine("Bye");
class yyy
System.Console.WriteLine("abc");
Compiler Warning
Output
at zzz.Main()
Here, a.abc calls the function abc in class yyy. System.Console.WriteLine is used to display
'Bye'. It is of significance to note that when you run this program the System.Console.WriteLine
does not get called. Hence the word 'Bye' is not displayed. Within the abc function we have a line
that says throw new System.Exception(); The word new indicates that we are creating an object.
We are creating an object that looks like System.Exception. 'throw' is a reserved word, that
means it is recognized by C#. Exception is a class in the System namespace. In other words, we
are identifying an exception, creating an object of it, and throwing it. Then we have a WriteLine
statement for printing 'abc'. Note that neither 'Bye' nor 'abc' gets displayed. A Message Box may
appear for debugging the applicaition. Since we are still at the learning stage, we click on the No
button.
The warning says that when you use the 'throw' keyword in your code, no lines of code get called
after that. Since the function abc is throwing an exception no code after the throw in abc will get
executed. The throw acts like the return statement. Everything comes to a stand still! And we get
an error at runtime and not at the time of running the compiler; indicating where the exception
occurred. Also no code gets called after function abc gets called as it throws an exception.
Explicitly declaring exceptions tells the compiler that a particular problem might occur. When
the problem does occur, an exception is thrown; the next step being to catch the exception. Let's
see how we can accomplish this. In our program, the function abc throws an exception. We will
now catch the exception.
a.cs
class zzz
yyy a;
a=new yyy();
try
a.abc();
System.Console.WriteLine("Bye");
catch (System.Exception e)
System.Console.WriteLine("After Exception");
class yyy {
System.Console.WriteLine("abc");
Output
at yyy.abc()
at zzz.Main()
After Exception
Catching exceptions is done within 'try-catch' blocks. Therefore, the code for abc is included
within a 'try-catch' block. a.abc - the function that throws the exception - is included within the
try-catch block . The abc function throws an exception by using the keyword throw. There is no
other way of throwing an exception. At this point all code is skipped in function abc as well as
the in the try block and the control moves to the catch block. As such, neither 'abc' nor 'bye' gets
displayed.
Within the catch we have a parameter 'e' that looks like System.Exception. The object e has a
method called ToString. ToString is a very handy function. It tells you where exactly the
exception occurred and in which function, function within function. So,
System.Console.Writeline will display the string 'In Exception' along with the exception.
After the code contained in the catch block is executed, the remaining code after the end of the
try - catch block will be executed. Hence, WriteLine will display 'After Exception'. That means
the program will not come to a stand still, it resumes execution after the catch and not after the
function which threw the exception. If you give a return statement immediately after the catch
block, as we have given in the next program, the program will stop execution there itself. Hence,
in this case, 'After Exception' will not be displayed as shown below.
a.cs
class zzz
yyy a;
a=new yyy();
try
a.abc();
System.Console.WriteLine("Bye");
catch (System.Exception e)
return;
}
System.Console.WriteLine("After Exception");
class yyy
System.Console.WriteLine("abc");
Output
at yyy.abc()
at zzz.Main()
Each time that abc gets called an exception is thrown. But you may not want that to happen.
Hence, exception handling is normally included in an if statement and if an error condition takes
place.
A 'try-catch' block can include a number of functions and whenever an exception occurs for any
one of them, we will catch it. By doing so we are synchronizing all the code to handle errors at
one place. Constructors can also throw exceptions.
Building Components
a.cs
System.Console.WriteLine("zzz abc");
The above program consists of a simple class zzz with one public function. The class has also
been tagged with the modifier public that makes it accessible to everyone. When we run the
command csc a.cs, we are asking the C# compiler to create an executable file for us even though
we did not explicitly ask it to. An executable file will always be created by the C# compiler
unless you override it by stating an option to the C# compiler. Let us start with the /t option.
You could use /t or /target. This option specifies what type of output file the compiler should
create for you. If you do not specify a /t option on the command line, C# by default writes /t:exe
for you thereby creating an executable file. The long form of /t is /target and depending upon the
time of day, choose the appropriate one. Not all options have a long and a short form like /t does.
The : after the option is mandatory. Then we write the type of executable output file we want.
Library means a dll. When we run the dir command we see a file named a.dll in the current sub
directory. A file with a .dll or a .exe extension are called Windows PE files. This is the default
file format that Windows uses to create executable files. There is a minor difference between the
internal structures of a dll and a exe file. Which is that a dll cannot be executed like an exe
program can. By convention dlls' are used to store code even though an exe could have also be
used. What we have done is created a component.
What if we wanted to change the name of the output file. By default it is the name of our
program. Then we must use the /out option as follows.
This will create a file bbb.dll instead of a.dll as earlier. Whether we use the /out option or not, C#
does it for us. If the C# program was called a.cs, then C# wrote /out:a.exe on the command line
for us. We can use the /out option to change the name of the output file. /out does not have a
short form /o.
Remember C# uses defaults for command line options to make life easier for us.
a.cs
class yyy
{
zzz a;
Compiler error
a.cs(5,1): error CS0246: The type or namespace name 'zzz' could not be found (are you missing a
using directive or an assembly reference?)
The only reason we create a component is to allow other programs to call code from it. In the
above program, we are saying that a looks like a class zzz. The C# compiler is telling us in a
vague way that it does not know that zzz is a class. Though we know zzz is a class as we just
created it and it is in a file called bbb.dll, C# is not aware of the same.
a.cs
class yyy {
zzz a;
Compiler Warning
a.cs(5,5): warning CS0168: The variable 'a' is declared but never used
The /r or reference option tells the C# compiler to look at bbb.dll; in this case for the code of
classes it is not aware of. In our case the error disappears as the file bbb.dll contains the code for
the class bbb.dll. Thus in future, if the C# compiler ever gives you the above error, do not panic.
All that you need to do is specify which dll contains the code for the classes. The help available
along with C#, tells you every class and the dll that contains the code of the class.
a.cs
class yyy
a.abc();
Output
zzz abc
We have successfully called the function abc in class zzz. The code of the class zzz resides in
bbb.dll.
a.cs
namespace mukhi
System.Console.WriteLine("zzz abc");
}
}
The same class zzz is now enclosed in a namespace mukhi and the component recreated.
a.cs
class yyy
a.abc();
Compiler Error
a.cs(5,1): error CS0246: The type or namespace name 'zzz' could not be found (are you missing a
using directive or an assembly reference?)
a.cs(6,1): error CS0246: The type or namespace name 'a' could not be found (are you missing a
using directive or an assembly reference?)
The error results as the name of the class is not zzz but mukhi.zzz.
a.cs
using mukhi;
class yyy {
a.abc();
Output
zzz abc
Databases
Databases are centralized stores of data. In a database, information from several files (also
known as tables) is accessed, coordinated and operated upon as if in a single file. Thus, the
database organizes data independently from the programs that access it. Large volumes of data
are stored in a database.
Computer programs have little meaning when written in isolation. Therefore, it is of importance
to have our programs work with databases. Databases work under the control of a database
management system. SQL Server is an RDBMS; it is one such database management system.
Before we can write programs that communicate with databases we need to have a database. One
of the simplest databases to use is Microsoft Access. As a large number of people use it, we have
based our examples on it. However you could use any RDBMS like Oracle, SQL Server as you
wish.
First and foremost, before we can access a database and perform various operations, we need to
connect to the database. Assuming you want to speak to your friend over the phone, you dial
your friend's phone number. Its only when you connect to your friends phone that the both of you
can speak to each other. Similarly, if we want to use a database we first have to connect to it and
only then can we speak to it.
a.cs
class zzz
System.Data.OleDb.OleDbConnection s;
}}
Compiler warning
a.cs(5,35): warning CS0168: The variable 's' is declared but never used
a.cs
class zzz
try
System.Data.OleDb.OleDbConnection s;
s = new System.Data.OleDb.OleDbConnection();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
Output
hell
Within the try block we have an object s that looks like System.Data.OleDb.OleDbConnection.
You are already aware that System is a namespace, but what about Data and OleDb? Well,
System.Data.OleDb is the name of the namespace. We can liken this to an earlier example where
we created a namespace mukhi.vijay. Hierarchy in a namespace can go to absurd lengths! The
help on C# states that System.Data.OleDb is the name of a namespace and OleDbConnection is a
class within that namespace. By saying s = System.Data.OleDb.OleDbConnection(); we are
creating the object s. When you run this program all that we see is the word hell, which means
that the constructor threw no Exception. If it did then the catch block would have been executed.
a.cs
class zzz
try
System.Data.OleDb.OleDbConnection s;
s = new System.Data.OleDb.OleDbConnection();
s.Open();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
}
Output
at System.Data.OleDb.OleDbConnection.Open()
at zzz.Main()
The class OleDbConnection has a function called Open which opens or connects to our database.
When we run the above the above program, the Open function throws an exception. Now, at this
point you must catch the Exception. The ToString within the catch block displays the Exception
message. The error says that the ConnectionString property has not been initialized.
The reason an exception occurred is that we did not provide certain mandatory information
whilst creating the object. We did not indicate the location of the database server that we want to
connect to or the database. It's like picking up the phone and not dialing a number. How in the
world do you expect to connect then!
a.cs
class zzz
try
System.Data.OleDb.OleDbConnection s;
s = new System.Data.OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb;");
s.Open();
System.Console.WriteLine("hell");
}
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
at System.Data.OleDb.OleDbConnection.InitializeProvider()
at System.Data.OleDb.OleDbConnection.Open()
at zzz.Main()
When you run the program, an OleDbException is thrown, which says could not find file
'c:\zzz.mdb'. This is because we have not created an MSAccess DataBase called zzz.mdb.
An mdb file stores data from multiple tables. In this file zzz.mdb, create one table abc with 2
fields f1 and f2 , both of type text. Add two records to this database. The first record will contain
1,a1 and the second record will be 2,a2.
Re run the program which now displays hell unlike before where we generated an Exception.
Output
hell
s.Open opens a connection to the database. The 'Provider' and 'Data Source' given in the
constructor identify the database.
As we have given the constructor all the mandatory information, s.Open() will open a connection
with the Access database. The program executes smoothly and once the connection is established
WriteLine displays 'hell'.
Now that we have established a connection with the database, let's see how we can communicate
with it. More specifically, let's see how we can execute an SQL command.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c.ExecuteNonQuery();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
Output
hell
Employing using, we do not have to preface every class with the namespace
System.Data.OleDb. The purpose of this program is to execute an SQL statement. SQL is a short
form for Structured Query Language. It is not a computer programming language like C# but
rather a language like English. SQL understands certain words like Create, which create a table
for us in our database. SQL has nothing to do with Oracle or Access, it works with all the
RDBMSs of the world.
The above SQL statement means that a table called a1 will be created in our database. It will
have 2 fields vno and name. Vno will store numbers and name will store characters subject to a
maximum of 10.
Thus we need one class to handle our connection to a database and another class which
understands SQL. We first create an object that looks like an OleDbConnection, which
understands how to connect to a database using a string attributes 'Provider' and 'Data Source',
which it passes as a parameter to the constructor. Then we create an object c which looks like
OleDbCommand as this class understands SQL. The constructor gets called with 2 parameters,
the SQL statement and also the connection object. Thus the object c now comprises the necessary
information regarding the command we want to execute and the connection. Now,
c.ExecuteNonQuery() will actually execute the SQL statement. ExecuteNonQuery() is a function
within the OleDbCommand class that enables us to execute any SQL command. You will now
see the word 'hell' displayed on your screen.
But did the table get created? Let's find out by starting Access and then choosing the database
zzz. Here we will see the table a1 with 2 fields vno and name but with no data at all. We created
our table alright, but it is empty as it has no data in it! So let's start inserting data/records into the
table. Before doing so, Quit out of Access
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c.ExecuteNonQuery();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}}
Output
hell
The only difference between this program and the previous one is that this one uses the Insert
SQL command. Earlier, we created a table zzz, now we are inserting records in zzz. To the
constructor of OleDbCommand we are giving two things - the insert command "insert into a1
values(1,'hi')" and the connection. Insert into and values are part of the SQL syntax. A1 is the
name of the table in which a fresh record will be added. After values, we write the data separated
by commas. The first field will contain 1 and the second hi. As the second field has the data type
of character, it has to be enclosed in single quotes. c.ExecuteNonQuery as usual executes the
SQL command and as no exception gets thrown ,the word 'hell' gets displayed..
Let's cross check to see if the data has been inserted into zzz by running Access. Aha! It displays
the record that you just inserted in the following format-
vno name
1 hi
Now it follows that if we can insert a record then we should be able to remove it too. The
following program uses the delete command to remove all the records from the table zzz.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
System.Console.WriteLine("hell");
catch(System.Exception e) {
System.Console.WriteLine(e.ToString());
Output
hell
Now c.ExecuteNonQuery will execute the delete command. This command deletes all the data
from the table. In Access we will see an empty table. This proves that the delete command was
successful!
Apart from inserting and deleting data another operation that is commonly performed is updating
data. However, you must have data in your table to update it. Our table is empty right now, so
let's execute the insert program once again. You will now have one record in your table zzz. After
inserting a record, change the sql insert command to an update command. This is shown below.
Here, we are giving an update statement and our connection to the object is 'c'. The update
statement will change the vno and name to the values specified. It will do so for any record that
has vno=1. We have only one record in our table and it meets this criteria. Now, go back to
Access , you will find that the record has been updated as follows-
vno name
3 bad
a.cs
using System.Data.OleDb;
class zzz
{
try
OleDbConnection s;
s.Open();
OleDbCommand c;
c.ExecuteNonQuery();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
System.Data.OleDb.OleDbException: The Microsoft Jet database engine cannot find the input
table or query 'a11'. Make sure it exists and that its name is spelled correctly.
at System.Data.OleDb.OleDbCommand.ExecuteCommand
TextErrorHandling(Int32 hr)
at System.Data.OleDb.OleDbCommand.ExecuteCommand
at System.Data.OleDb.OleDbCommand.
ExecuteCommandText(Object& executeResult)
at System.Data.OleDb.OleDbCommand.
at System.Data.OleDb.OleDbCommand.
at System.Data.OleDb.OleDbCommand.ExecuteNonQuery()
at zzz.Main()
Don't worry, we have simulated this error on purpose. The table a11 does not exist in our
database. Thus an exception got thrown by ExecuteCommandText and not ExecuteNonQuery as
seen above. What it means is that ExecuteNonQuery calls Execute which calls ExecuteCommand
which finally calls ExecuteCommandText. Also the word hell does not get displayed because of
the exception thrown.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
hell
We have executed different SQL commands through our earlier programs. We will now try and
execute an SQL select statement. In order to do so, we have given the following select statement
to the constructor along with the connection- 'Select * from abc'. Abc is a table in the database
called zzz . Remember, c looks like OleDbCommand. 'Select' is part of the SQL syntax like
insert , update . 'from' is also a reserved word . 'abc' is the name of the table created earlier in
Access and populated by data keyed in by us. The '*' means all fields in the table. We could have
also replaced the * with a comma separating list of field names that we were interested in.
The function ExecuteReader will create an object that looks like OleDbDataReader and initialize
r to it. No exception was thrown, which meant no errors from our side.
What we need to do now is retrieve data from the abc table. The abc table may have ten fields
and twenty records. So we use what is called a 'dataset'. In other words, how do we access data
contained in multiple rows and multiple columns through our program? For example, when we
run the select statement it gives us the data in rows and columns. How can we achieve this
through our program? To do that we now need a third object which looks like OleDbDataReader.
We can almost feel your dismay - Oh no! Another object! Well, there is a very good reason why
you need to have three different objects. Firstly, you need an object that understands a
connection. Then you need another object that understands an SQL statement. This is because
somebody has to execute that statement. You now need a third object that will let you
read/retrieve data. That is why we have 'r' an object that looks like OleDbDataReader. Thereafter,
we have c.ExecuteReader. Earlier we used a function call ExecuteNonQuery. This is because in
case of an insert, update or delete we didn't want any data to be retrieved, we didn't want an
answer back!!
As a recap, we are using r to store the value return by ExecuteReader. That means r will be filled
up by ExecuteReader. On executing this program only 'hell' is displayed.
Now that we have the filled up r, let's see how we can display the data.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c=new OleDbCommand("select * from abc",s);
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("{0},{1}",r.GetValue(0),r.GetValue(1));
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
at System.Data.OleDb.OleDbDataReader.DoValueCheck(Int32 ordinal)
at System.Data.OleDb.OleDbDataReader.GetValue(Int32 ordinal)
at zzz.Main()
Run this program. Expect the unexpected....an error! The error says 'No data exists for the
row/column' But didn't the function Execute fill up r? It did, but it did not position the record
pointer on the first record. A record pointer is an abstract concept. To start with it appears just
before the first record. The function GetValue will return the value of the fields depending upon
where the record pointer is. At the start it is just before the first record. So r can be also looked at
as an array that contains all the fields. We get an error because we need to read the data into our
array first. In order to read data into the fields we must give r.Read. Without r.Read, the records
will not be read into the array, so also the record pointer will not be moved forward to the first
record.
Now that we know the reason why the error occurred let's rectify it by doing the needful. Let's
add r.Read() to our program.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine(r.Read());
System.Console.WriteLine("{0},{1}",r.GetValue(0),r.GetValue(1));
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
}
Output
True
1,a1
Now that we have added r.Read() the program executes as advertised. r.Read() returns true.
Thereafter, the GetValue() function which needs the field number as a parameter retrieves the
data associated with the first and second column. Remember in C# we start counting from zero
and hence zero as a parameter to GetValue will retrieve the value of field one in the table. The
datatype of the first field is numeric and of the second character. However, the function GetValue
does not seem to care.
Read returns true if more data is available to read and false if it is at the last record. Also read
positions the record pointer to the next record.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c=new OleDbCommand("select * from abc",s);
OleDbDataReader r;
r = c.ExecuteReader();
while (r.Read())
System.Console.WriteLine("{0},{1}",r.GetValue(0),r.GetValue(1));
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
1,a1
2,a2
(A display of only the first two fields of all the records in the table. )
But now we want to display all the data in the fields. So we are using Read in a loop.
while(r.Read()). r.Read() returns true as long as it can read data. The while loop continues till the
condition is true. We are using our trusted function WriteLine to display the data of the first and
second field. Thus the moment r.Read() cannot read more data it returns false and the while loop
terminates. Now all the data in the two fields is displayed and as such we have a long list of data
displayed. To verify further, add some more fields and records to abc.
Just as we mind our manners in daily life we must do so in programming too. It is a good
practice to shut the door when leaving a room. Similarly, in programs we must close what ever
we opened.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
while (r.Read())
System.Console.WriteLine("{0},{1}",r.GetValue(0),r.GetValue(1));
r.Close();
s.Close();
System.Console.WriteLine("hell");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
Output
1,a1
2,a2
We will mind our manners and give r.Close() and s.Close. Note that it is not mandatory to do so.
First we are closing r and then we are closing s i.e. the connection that we opened.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine(r.FieldCount);
System.Console.WriteLine(r.GetName(i));
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
f1
f2
An OleDbDataReader has a useful function called FieldCount which tells you how many fields
the SQL statement contained. In our case abc has two fields. We have one more function
GetName which will tell us the name of the function in the table given the field number. Thus
r.GetName(1) will give us the name of the 2nd field. In the for statement, the variable i starts at
zero. The condition becomes false when the value of i is one less than r.FieldCount which in this
case is 2 i.e. i will take values of 0 and 1. The reason being i starts from zero as GetName
understands zero as the first field. Thus we can now print all the column names using the for.
Now lets print the entire table irrespective of the number of columns or the number of rows.
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
while ( r.Read() )
System.Console.Write(r.GetValue(i)+" ");
System.Console.WriteLine();
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
}
Output
1 a1
2 a2
You can modify abc to add more fields and fill in more records. Execute the program and see the
change in output. Whenever we do not know better, we use a for or a while i.e. a looping
construct. However we do not know two things. One, the numbers of rows in the table and two
the number of columns. The first while takes care of the number of rows and the for, the variable
number of columns. Thus the above program will work for any number of columns and rows in
the table. All that we do is change the select statement. The difference between Write and
WriteLine is that Write does not add an enter at the end like WriteLine does. Also + is used to
join two strings together. We are adding a space at the end of every field as a separator.
5
Web Enabling Data
We now have to our credit, programs that enable execution of a general purpose select statement
as well as those that update, insert and delete commands. These were all C# programs which
were compiled into executable files.
Let's assume you want to display the contents of the customer table. Our program will very well
serve this purpose. Alternatively, the program can be made to accept user input and depending
upon the table name that the user typed in, the program can display contents of that table. You
can easily do so with the help of a function called GetLine in Console. GetLine will cause the
program to wait at the console for the user input followed by the 'Enter' key.
This situation comes with its share of problems though. The problem is that if there are five
people who are going to use this program then you need to give them five copies of the program.
If there are five thousand such users then you have to copy this on to five thousand different
machines. Simply not possible. Wait a minute! Did you get a sudden brainwave? The perfect
solution would be to 'put it on a network'!! But don't forget that there are many networking
standards available. Some may have Novell, some may have Windows 2000, and others may
have the Macintosh or even Linux/Unix. So what do we do now? You will have to make sure that
the same program works under Linux as well as it does under a Mac or any other standard. Apart
from this you would have the headache of having to train people to use the program.
The only solution to this problem is Web enabling data. This is the new standard of writing code.
You need to access your data using Internet Technologies. It's only then that we can eliminate the
loopholes that exist within the already available standards.
No matter which operating system you install, along with it you get access to a browser. When
you use the Internet you use a browser, a.k.a. an user agent, that enables you to view web pages
and enables data transfer over the Internet.
Since we do have a browser, can't we do a simple thing? Let the user type the name of our
machine and get a form. Within the form he can key in the table name and once he does that he
will get the details of that table. Which means you will now have to execute your code on a
program called the WebServer. This is what is meant by Web Enabling Data.
But before we leapfrog into the world of Web Enabling Data, let's acquaint ourselves with the
basic language that the browser understands. It is called HTML.
HTML
Amongst browsers, the usual suspects are Netscape Navigator and Internet Explorer. What
happens when you view a web page using such a browser? Technically speaking, you connect to
a web server and a file comes over onto your computer, which is generally an HTML file.
HTML is the acronym for Hyper Text Markup Language. It is a document-formatting language.
HTML is basically a stream of characters without any intelligent functionalities like the for and if
statements. Hence it cannot be considered an equivalent of a programming language. HTML, as
simple as it is, allows any bumpkin to be an ace at it!
Assuming you have a Web Browser, let's write our first HTML program. You can use any editor
like word to type your program in. The only thing that you must bear in mind is that the file must
be saved with the extension .htm or .html. Create the file in your root directory. In our case, we
will save in c: and since we are using the dos editor we shall begin by saying edit a.html
C:>edit a.html
a.html
Hi
Bye
Output
Hi Bye
Note that the text must be on two separate lines. Once you have saved your file run your browser.
In the browser you will see a white text box known as the address bar. Click there and type
c:/a.html, in our case we have saved the file in the root of the C drive.
As of now we are picking up this html file from our hard disk. But when you are on the Net you
are accessing a file from some other machine on the net. In that case, you give the address of that
machine. For instance, if you want to connect to the Microsoft site, you will type
www.microsoft.com. Apart from that there is no difference in trying this on the Net or off the
Net.
When the browser sees an html file, it reads it line by line. Hence, in the browser window you
will see Hi Bye displayed. Wow! You have just written your first html program!
But didn't we write Hi and Bye on two separate lines? The browser, dumb as it is doesn't seem to
understand this. Looks like the browser, by default, ignores enters! So, how can we make the
browser understand? We can do so with the help of 'tags'.
HTML is based on 'tags', which instruct the browser how to display a piece of text or an
image/picture. A tag begins with '<' and ends with '>'.
a.html
Hi <br>
Bye
Output
Hi
Bye
Going by the definition of a tag you will realize that br is a tag. It is enclosed within the angular
brackets. <br> means next line. Save the file. Now when you view this file in the browser you
will find that Hi and Bye are displayed on two separate lines.
Hence, HTML is nothing but a collection of tags. You just need to know which tag satisfies what
purpose.
a.html
Bye
Output
Hi
Bye
In this program, the tag b means bold. But here we also have </b>, which is a closing tag. This
indicates that we are closing the <b> tag. Whatever is enclosed between the two will be made
bold. Hence only Hi will be bold. HTML tags are romantic, most of them always travel in pairs -
called an opening tag and a closing tag. But some tags like <br> like to play the field for they
prefer to remain single.
Bye
Output
Hi
Bye
It is all very mechanical! <i> means italics and hence Hi is displayed in italics. Had you included
bye within <i> and </i> then bye would be in italics too! That's all the understanding that is
required to learn HTML!
a.html
Output
Hi
Bye
Since Hi is included in <i> </i> it will be displayed in italics. Bye is displayed in bold due to the
<b> tag. <hi> means heading1, it makes the text bigger. Thus, 'You are Welcome again!' is
displayed in a bigger font.
a.html
<html>
<body>
</body>
</html>
Output
Hi
Bye
This program outputs the same result as the above. The only difference is that now it is a well-
formed HTML program. Every HTML file must begin with the <html> and end with </html>
tag. Whatever text is to be displayed within the browser must be enclosed within the <body> and
</body> tag. This is the way an HTML program must be written. Hope the purists have forgiven
us now!
Let's make our page attractive by adding a picture to it. Copy any gif file to your root directory
and name it aa.gif. In our case, we copied it to c:
a.html
<html>
<body>
<img src="aa.gif">
</body>
</html>
img is the image tag, it is used to display pictures. Along with this tag you have to specify the
name of the image file. Following the word 'img' is the word 'src' and after the '=' sign you
specify your filename. i.e. aa.gif. You can give the name of any picture file. But follow this
syntax! Another thing to note is that you can have the file name included in single quotes or
double quotes or you may exclude them totally. Thus viewing this file in the browser will now
display the image you specified along with the text. In HTML parlance, src is called an attribute.
An attribute describes / qualifies a tag.
You will see two hyperlinks in your browser window. The names of the html files will not be
displayed but the words Hi and Bye will be underlined. And if you click on hi and bye the
respective html files will be displayed instead.
a.html
<html>
<table border=10>
<tr>
<td>hi</td><td>100</td>
</tr>
<tr>
<td>1000</td><td>bye</td>
</tr>
</table>
</html>
The table tag has one attribute, border, that specifies how the lines or borders between columns
looks like. The table tag encompasses two tags . tr stands for a table row and td for a table
columns. We have two tr's , hence we have two rows and each tr encloses two td's one for each
column.
Similarly, you can keep adding more and more tags depending on how you want your page to be
displayed. Any book on HTML will list all the available tags. Our aim is not to learn html here
but to use C# on the Net. Since knowing this much will suffice our forthcoming needs, let's get
back on track!
Using C# on the Net
Now that you are familiar with the rudimentary elements of HTML, let's see how we can apply
our recently acquired knowledge in conjunction with C# on the Net.
First and foremost you need a Web Server. Hence you will now need to install Apache. You can
download Apache from http://www.apache.org and then run the installer program. Among the
Apache directories, there are two sub-directories that are of importance to us, namely, cgi-bin
and htdocs.
In order to change to the cgi-bin sub-directory follow the path as given below.
C:\progra~1\apache~1\apache\cgi-bin
C:\progra~1\apache~1\apache\htdocs
To install the Apache Web Server all that you need to do is download the install program on your
hard disk. Run the executable program which will install apache in the apache group directory of
program files. Change to C:\progra~1\apache~1\apache directory and then run the web server as
follows.
C:\progra~1\apache~1\apache >apache
If you get an error about some server name, cd to the conf sub directory , edit a file called
httpd.conf , change a line starting with #ServerName to ServerName localhost and all should be
well after that.
Now that you have the Apache server running, activate your web browser. Type the address
127.0.0.1 in the address bar and press enter. Every machine on the internet is known by a
number. We call this number an IP address. IP stands for the Internet Protocol. Every machine
that has the Internet software running is also known by the number 127.0.0.1 or localhost. In case
a file called index.html exists, the browser will display it. This is because it is located in htdocs
and is the file that gets picked up by default when you give your machine address and you have
Apache running.
Change to the htdocs sub-directory and create an html file a.html to display a form.
a.html
<html>
<form>
<form>
</html>
The <form> tag is used to specify that we are creating a form. <input type=submit is the syntax
for creating a button. Value =Search means that 'Search' is the word that will appear on the
button. Had we said Value = Vijay, you would see the 'vijay' on the button.
Save the file as a.html in the htdocs subdirectory. Go to the browser window and type
http://127.0.0.1/a.html in the address bar and press enter. You will now see a button with the
name Search on it. But clicking on this button doesn't serve any purpose as of now.
Let's alter the program such that when the user clicks on the Search button our C# program
should execute.
C:\csharp>edit a.cs
a.cs
class zzz
System.Console.WriteLine("hi<b>bye");
Output
hi<b>bye
This is a simple program that should display hi and bye. Save the program as a.cs. On compiling
the program an executable file 'a' is created. If you run the program as we have been doing, you
will see the output as given above. But remember, what we just told you about executables?
When you are using Apache you must save all executables in the cgi-bin sub-directory as a
security precaution. Hence you must copy a.exe to cgi-bin by giving the following command.
Now we will alter our HTML program. Within the form tag include action=http://127.0.0.1/cgi-
bin/a.exe This indicates the action to be performed when the button is clicked. Since we want our
program a.exe to run, we have given its path.
a.html
<html>
<form action=http://127.0.0.1/cgi-bin/a.exe>
<form>
</html>
Now that we have everything ready, let's get on with the show! Activate your browser and type
http://127.0.0.1/a.html in the address bar. You see the button labeled Search. Now click on this
button. To your horror you see an error! The browser window displays an Internal Server Error.
Note the url in the address bar- http://127.0.0.1/cgi-bin/a.exe?
a.cs
class zzz
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine("hi<b>bye");
}
}
Output in Browser
hibye
Save your file, compile it and again copy it to cgi-bin once again. Now when you run your
program from the browser, the error vanishes! And you will see hibye displayed. That means it is
mandatory to give Content-Type. It tells the browser that what is being sent across is a text file.
Also the content is qualified as html and not pure text. It is also called a header. Because we are
saying html, the bye is displayed in bold. So we created a file and the file goes over i.e. what
ever is in Console.WriteLine goes over.
Now remove html and instead write plain. Let's see what happens. After making the necessary
changes and compiling the program copy it again to cgi-bin.
a.cs
class zzz
System.Console.WriteLine("Content-Type:text/plain\n");
System.Console.WriteLine("hi<b>bye");
Output in Browser
hi<b>bye
Now run your program from the browser. You will notice that bye is not displayed in bold. Also
note that now the tags are displayed as normal text. They show no formatting effects. This is
because instead of the word html we are now saying plain. That means the browser will now
display everything as plain text.
Thus the Content-Type: header is used to indicate to the browser that we are sending text
followed by HTML. Thus if we want our program to execute on the web it is mandatory that we
include this header in our program as the web server does not know what is the file type it is
sending over.
Now that we have all the ingredients for the final show, let's get on with it. We will now add the
header to our general-purpose select program. We will do this so that we can display the contents
of a table on the web. Thus the only change that we have made to the program is to add the
following line:
System.Console.WriteLine("Content-Type:text/html\n");
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("Content-Type:text/html\n");
while ( r.Read() )
{
System.Console.Write(r.GetValue(i)+" ");
System.Console.WriteLine(“<br>”);
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Now save the file and compile it. Copy the file a.exe to the cgi-bin sub-directory. Activate the
browser window and type http://127.0.0.1/a.html in the address bar. Now click on the search
button. Accolades! You have successfully run your C# program from the browser. You will now
see all the contents of the abc table. Why the abc table? Because that's the table you specified in
your program.
Thus, whenever the user clicks on the button in the browser he is calling a program on the server.
The server could be a trillion miles away!! However, even now everything is not hunky dory.
The major problem being that this entire approach is inflexible.
Earlier, we told you we need this type of programming because we didn't want to copy the
programs on each machine. But the problem with the Web Server is that if it contains ten html
files then we can give the user only those ten html files. So we are only giving him ten views.
However, what we really need to do is that we need to pass data from us to his machine.
For example, let's assume we have a database that has names of people. We should have a form
in which the user can write the name of a person. When he clicks on 'ok' that name should get
added to the database. In effect, we are adding one person’s data to the database. Similarly, we
should be able to delete a person from the database too. And finally we can have a table-display
program wherein the user will provide the table name. When he clicks on ok, the contents of that
table will be displayed. Thus you can now think of generating flexible programs. You probably
felt limited earlier as you could display contents of only that table whose name you had provided
within the program.
Environmental Variables
Before we get down to making our programs flexible we need to understand as to how we can
deal with Environmental Variables in C#. An Environmental Variable is a word that the operating
system understands.
a.cs
class zzz
string s;
System.Console.WriteLine("Content-Type:text/html\n");
s=System.Environment.GetEnvironmentVariable("PATH");
System.Console.WriteLine(s);
Output
Content-Type:text/html
C:\JDK1.2.2\BIN; C:\WINDOWS\MICROSOFT.NET\FRAMEWORK\V1.0.2204\;
C:\WINDOWS; C:\WINDOWS\COMMAND; C:\BORLANDC\BIN; C:\WINDOWS;
C:\WINDOWS\COMMAND; C:\PROGRAM FILES\MTS
Displays the value of environmental variable called PATH. An environmental variable is a word,
which stores a value. When you give the command set xyz=bye at the command prompt, xyz
becomes an environmental variable, which stores the value bye. All operating systems allow you
to create environmental variables . The environmental variable PATH stores a list of directories
that the operating system searches for to find executables files. Run it off the web server or by
itself.
a.cs
class zzz
System.Collections.IDictionary i;
i=System.Environment.GetEnvironmentVariables ();
System.Collections.IDictionaryEnumerator d;
d=i.GetEnumerator();
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine(i.Count + "<br>");
while (d.MoveNext())
System.Console.WriteLine("{0}={1}<br>",d.Key,d.Value);
There can be 100's of environmental variables and we would like a list of all of them. The class
Environment in the System namespace has a function GetEnvironmentVariables which returns an
object that looks like IDictionary. This IDictionary object has a function called GetEnumerator
which returns an object that looks like IDictionaryEnumerator. You have to learn all this by rote,
there is no other option available. We are then displaying how many environmental variables
there are by printing a member Count in IDictionary. Then we need to activate each variable by
calling MoveNext which returns true if there are more environmental variables in the list. An
environmental variable is represented by a key-value pair, which is also variable in the
IDictionaryEnumerator class. Thus we can display all the environmental variables starting with a
count of how many there are.
If you check the list of environmental variables in your browser, you will see one called
QUERY_STRING , but it will have no value.
Now run as http://127.0.0.1/cgi-bin/a.exe?aa=ho and see the variable QUERY_STRING have a
value aa=ho.
a.html
<html>
<form action=http://127.0.0.1/cgi-bin/a.exe>
<form>
</html>
Run the file in the browser. And you will now see a text box which is internally called aa. This is
because of the tag input type=text. Type ho in the text box and click on search. The URL will
now change to http://127.0.0.1/cgi-bin/a.exe?aa=ho and the variable QUERY_STRING will have
the value aa=ho.
a.html
<html>
<form>
</html>
Now we will see two text boxes in which we will type in ho and no. Click on Search and the url
will change to http://127.0.0.1/cgi-bin/a.exe?aa=ho&bb=no and the variable QUERY_STRING
will have the value aa=ho&bb=no.
CGI Programming
Let us now understand what goes on once again. What we have been trying to explain to you is
called CGI programming where CGI stands for Common Gateway Interface. Everyone refers to
by its acronym rather than its expanded full form. CGI is a means by which a client i.e. a browser
can send some information to the web server.
Now typically what happens when we land up at a search engine? Well, we want to send the web
server i.e. yahoo the words that we want it to search the internet for. At times we are asked to fill
up a form on the web asking for some personal details. The information we key in is sent across
to the web server. Lets start with the above HTML file that makes CGI happen. We have two
input tags which have an attribute type=text. Thus we see two text boxes on our screen. We will
type in them hi and bye respectively. The third input tag has a type=submit and another attribute
value=search. This makes it into a button with the word search written on it.
Now, when we click on search after typing in data in the text boxes, the browser knows that you
have clicked on a button of type submit. So, it will now look for a tag form , and when it finds it ,
it will read the attribute action. Whatever is the value of action, it will write it in the address bar.
In the address bar we write a URL or Uniform Resource Locator or the address of a computer on
the net. In our specific case, our browser's address bar will contain http://127.0.0.1/cgi-bin/a.exe.
The browser does not stop here. It then adds a ? to the end of the above URL . Now it looks at
every text box that we have in the form. The first one has been given a name aa and we type hi in
it. So our URL now changes to http://127.0.0.1/cgi-bin/a.exe?aa=hi.
It's not over yet as we have one more text box to finish with. This one is called bb and has bye in
it. Thus our URL now reads http://127.0.0.1/cgi-bin/a.exe?aa=hi&bb=bye. The & is used to
separate different parameters. aa and bb are also called parameters. This url is sent across to the
web server. The web server is just another name for a file server. It can only send files across. In
this case we are asking it to run a program called a.exe from the cgi-bin sub directory. Before the
web server runs a.exe, it creates one environmental variable called QUERY_STRING and
initializes it to whatever follows the ? i.e. in this case aa=hi&bb=bye. The web server now runs
a.exe. What a.exe actually does is none of its concern. All that is wants from a.exe is a html file
which the web server sends back to the browser.
The web server also needs at least one header Content-Type which tells it the type of file being
sent across. Normally a.exe would read the environmental variable QUERY_STRING, extract
the parameters, then read a database, extract some values from it and finally create an HTML file
which it would hand over to the web server. All in all, this is how the magic of the internet is
bought about.
a.cs
class zzz
string [] e;
char[] c ;
s = "hi=bye&no=bad" ;
c = new char[2];
c[0] = '&';
c[1] = '=';
e = s.Split(c);
foreach ( string t in e)
System.Console.WriteLine(t);
Output
hi
bye
no
bad
s is a string which has been initialized to hi=bye&no=bad which looks similar to what
QUERY_STRING as explained earlier looks like. C is an array of chars which has two members
initialized to & and = respectively. The string class has a member Split, which will split a string
as per the delimiters provided as the first parameters in an array of chars. Thus the split function
will take the string s and split it whenever it sees a & or a = . In this case it will result in 4
strings. Split returns an array of strings which we are storing in an array e and using foreach to
display the array.
Now lets us create a simple form based web application which will accept a table name and then
display the entire table for us.
The html file a.html as usual will be copied to the htdocs sub-directory.
a.html
<html>
<form>
</html>
http://127.0.0.1/a.html
Our C# program freshly compiled and copied to the cgi-bin subdirectory would now read as:
a.cs
using System.Data.OleDb;
class zzz
try
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
string [] u;
u = t.Split(v);
string w;
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c=new OleDbCommand(w,s);
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("Content-Type:text/html\n");
while ( r.Read() )
System.Console.Write(r.GetValue(i)+" ");
System.Console.WriteLine("<br>");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
At our web form we are asked to write the name of the table. Then click on the button Show
Table. The web browser now writes the following URL in the address bar after we wrote abc as
the name of our table. http://127.0.0.1/cgi-bin/a.exe?aa=abc. The Apache Web Server now runs
a.exe. a.exe is nearly similar to what we wrote earlier with some minor modifications. t contains
the value of the environmental variable QUERY_STRING . v is an array of chars with one
member which is our delimiter '='. Split will return an array of strings in u , in our case aa and
abc which will be stored in u[0] and u[1]. Earlier we hard-coded the SQL Select statement. Here
w starts with the constant string 'Select * from ' and the name of the table is got from u[1] which
in turn gets its value from the environmental variable QUERY_STRING. Write the name of any
table that exists in the database in the text box and see how you have been able to web enable
your data on the net.
Lets use the table tags to make our data look more appealing in the browser.
a.cs
using System.Data.OleDb;
class zzz
try
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
string [] u;
v[0] = '=';
u = t.Split(v);
string w;
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
c=new OleDbCommand(w,s);
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine("<table border=10>");
while ( r.Read() )
System.Console.WriteLine("<tr>");
System.Console.WriteLine("</tr>");
System.Console.WriteLine("</table>");
}
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
The output looks great. We have made very small additions to our program, mostly cosmetic. We
start with the table tag with a border. The while gets called once for every record and in this
while we start and end with a row tag tr and /tr. The for gets called for every field and here we
enclose the field value with a tag td and /td. At the end of the while we end with the /table tag.
The only problem is that we have not displayed the field names at all. Let the next program do
so.
a.cs
using System.Data.OleDb;
class zzz
try
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
string [] u;
v[0] = '=';
u = t.Split(v);
string w;
OleDbConnection s;
s.Open();
OleDbCommand c;
c=new OleDbCommand(w,s);
OleDbDataReader r;
r = c.ExecuteReader();
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine("<table border=10>");
System.Console.WriteLine("<tr>");
System.Console.WriteLine("</tr>");
while ( r.Read() )
System.Console.WriteLine("<tr>");
System.Console.WriteLine("</tr>");
}
System.Console.WriteLine("</table>");
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
All that we did was to copy the for loop which generated the field names from an earlier
program. We put a tr and a /tr around the for loop and the names of fields are tagged with td.
Great looking output.
a.cs
class zzz
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine(t);
Output
aa=select+*+from+abc
In the original a.html instead of writing a simple table name we wrote ‘select * from abc’ instead.
When we displayed the environment variable QUERY_STRING we learn that the spaces are
replaced with a + sign. The rules of creating a URL specify that a space is a forbidden character
and all spaces that we write are replaced by a +. Thus we have to convert the + back into spaces.
a.cs
class zzz
string t,s;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
System.Console.WriteLine("Content-Type:text/html\n");
s = t.Replace('+',' ');
System.Console.WriteLine(s + "<br>");
System.Console.WriteLine(t);
Output
aa=select+*+from+abc
The string class has a method called replace which replaces every occurrence of the first
parameter i.e. + with the second i.e. a space. Thus s is t but with the plus sign replaced by a
space.
Lets us know write an insert statement which will ask the user to key in his first and last name
and then add it into a table. We create a table 'bbb' in our database with two fields f1 and f2 both
character type. Our html file also now changes to.
a.html
<html>
<form>
</html>
a.cs
using System.Data.OleDb;
class zzz
try
OleDbConnection s;
s = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\zzz.mdb");
s.Open();
OleDbCommand c;
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
string [] u;
v[0] = '=';
v[1] = '&';
u = t.Split(v);
string f1,f2,f3;
f1 = u[1].Replace('+',' ');
f2 = u[3].Replace('+',' ');
System.Console.WriteLine("Content-Type:text/html\n");
System.Console.WriteLine(f3);
c=new OleDbCommand(f3,s);
c.ExecuteNonQuery();
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
Output
http://127.0.0.1/cgi-bin/a.exe?aa=vijay+ram&bb=mukhi
The first change is that our array of chars is now two members large and the second delimiter is
the '&'. Thus our QUERY_STRING will break into 4 strings aa , vijay+ram , bb and mukhi in
u[0] to u[3]. We replace the + with the ' ' in both strings and dynamically generate the insert
statement. It looks confusing but is not, Once again f1 and f2 contain the dynamic data but
because they are strings we need them to be separated by a single inverted comma. Thus the
complication in concatenating strings. The browser displays the SQL statement that will be
executed, but in real life we would display a success or error message.
Now let us write a search engine or more precisely, a general purpose data retrieval engine. For
which we have to first create a simple database that will contain the following fields :
and finally the text that will be displayed explaining the page.
create table ss ( keyword char(10), url char(100), name char(100), descrip char(100));
insert into ss values ( 'java', 'a.html', 'java site', 'great java site');
insert into ss values ( 'basic', 'c.html', 'basic site', 'great basic site');
insert into ss values ( 'cobol', 'd.html', 'cobol site', 'great cobol site');
search.html
<html>
<form>
</html>
a.html
b.html
c.html
d.html
a.cs
using System.Data.OleDb;
class zzz
try
string t;
t=System.Environment.GetEnvironmentVariable("QUERY_STRING");
string [] u;
v[0] = '=';
u = t.Split(v);
string w;
System.Console.WriteLine("Content-Type:text/html\n");
OleDbConnection s;
s.Open();
OleDbCommand c;
c=new OleDbCommand(w,s);
OleDbDataReader r;
r = c.ExecuteReader();
while ( r.Read() )
catch(System.Exception e)
System.Console.WriteLine(e.ToString());
}
}
All that this program does is use the concept of a hyperlink to build a search engine and extract
data from a database. We assume we have a database of a trillion records that map the internet
telling us the keywords that each url stands for. The user keys in the name of a language and we
use the select statement to fetch the records meeting the condition, format it and then send the
html file across.
We can use the same concept to fill up a list box. The html tags for list box are as follows
<option> red</option>
</select>
In a real life situation, the colours will be retrieved from a database and the HTML file generated
by a CGI program.
6
Miscellaneous
Multiple files
A C# program can be spread over multiple files. So far all our code has been written in one large
file. Lets us create 2 .cs files a.cs and b.cs as follows
a.cs
class zzz
a.abc();
b.cs
System.Console.WriteLine("hi");
}
Earlier our code did not spawn multiple files. C# does not care whether the code is in one file or
spread over multiple files. We have only to make a small change while we compile the program.
Output
Hi
These files are called source files and it is a good idea to give them a file extension of .cs. If you
rename b.cs to b.xxx as we did and rerun csc as
This will create a.exe as usual. File extensions matter to the programmer not to the compiler.
a.cs
class zzz
System.Console.WriteLine((char)65);
System.Console.WriteLine((char)66);
System.Console.WriteLine((char)67);
Output
A
B
Computers in a way are pretty dumb. They do not understand letters of the alphabet. All that they
can store in memory are numbers. But then, how does a computer understand or display
alphabets? The WriteLine function displays 65 as 65, but the output is A. In the () brackets we
have placed a data type called char. We call a ( ) a cast. It means, for the moment convert
whatever follows into a char. Thus the number 65 gets converted into a char which is displayed
as a 'A'. The 66 gets displayed as a 'B'. Someone, somewhere in the world invented a rule which
specified that the number 65 represents a capital A, etc. This rule is given a name and is called
ASCII. All that ASCII says is that the numbers form 0 to 255 can also represent small and capital
letters, punctuation etc. Whenever you write A, rest assured somewhere in memory, a 65 was
stored. A file on disk can also contain numbers form 0 to 255 only and the same rule as spelt
above apply.
a.cs
class zzz
char i = 'a';
System.Console.WriteLine((char)i);
Output
a.cs
class zzz
{
public static void Main()
int i;
The above program displays the entire Ascii table. The problem with Ascii is that it is sufficient
for a language like English, which does not have to many symbols to represent. However, when
it comes to visual languages like Japanese, they have more symbols to represent than English.
Ascii can represent a max of 256 unique symbols. The industry thus invented Unicode which
uses 2 bytes for every character unlike Ascii's one. All the languages of the world can be
represented by Unicode. C# understands Unicode and thus the char data type store characters
internally as Unicode and not Ascii.
a.cs
class zzz
int int;
Compiler Error
a.cs
class zzz
int @int;
Compiler Warning
a.cs(5,5): warning CS0168: The variable 'int' is declared but never used
The warning does not name the variable @int but int.
a.cs
class zzz
int @int;
@int = 10;
System.Console.WriteLine(@int);
}
Output
10
We have millions of names to choose for a variable, then why insist on an int. There will be
times when another language declares a name as a reserved name and in those cases we would
use the @ sign. It is advisable not to use the @ sign very often.
When we run the C# compiler on our program, it does 2 things. One, it reads our code and
converts it into things/tokens it understands. This is called a Lexical analysis. Then it does a
Syntactic analysis which gives us an executable output.
Comments
Comments are a form of documentation. They are lines of code written for our benefit (the
community of programmers) and not for C#'s. In spite of this, programmers in general are lazy in
writing comments. Comments are ignored by the compiler.
a.cs
// hi this is comment
class zzz
/*
A comment over
two lines
*/
A regular comment starts with a /* and ends with a */. They can be spread over multiple lines
and can be placed anywhere in your code. Any line beginning with a // is a one line comment and
as the name suggests, cannot span multiple lines. A single line comment does not have to be at
the beginning of a line.
Escape Sequences and Strings
a.cs
class zzz
System.Console.WriteLine("hi \nBye\tNo");
System.Console.WriteLine("\\");
Output
hi
Bye No
An escape sequence is anything that starts with a \. A \n means start printing from a new line and
a \t means a tab. Two backslashes convert into a single backslash.
a.cs
class zzz
System.Console.WriteLine(@"hi \nBye\tNo");
}
Output
hi \nBye\tNo
A string is anything in double quotes. A verbatim string starts with a @ sign and all the escape
sequences are ignored by the C# compiler and displayed verbatim.
a.cs
class zzz
System.Console.WriteLine("hi
bye");
Compiler Error
a.cs
class zzz
System.Console.WriteLine(@"hi
bye");
}
Output
hi
bye
Placing an @ in front of the string lets it spawn multiple lines and the spaces shown in the
output. If you want the \ to lose its special meaning in a string, preface that string with a @ sign.
a.cs
class zzz
string a = "bye";
string b = "bye";
System.Console.WriteLine(a == b);
Output
True
The above example displays true, even though the two strings may be stored in different areas of
memory. The two strings contain the same characters and hence are similar.
The Preprocessor
Before the C# compiler can start, a small part of it called the pre-processor first activates itself. It
is called the preprocessor as the same concept existed in the programming language 'C'. All that
the preprocessor does is that it looks at those lines beginning with a # symbol.
a.cs
#define vijay
class zzz
The first preprocessor directive we are learning is called define. This lets us create a
word/variable or even better, an identifier called vijay. The identifier vijay has no value other
than true.
a.cs
class zzz
#define vijay
Compiler Error
a.cs(5,2): error CS1032: Cannot define/undefine preprocessor symbols after first token in file
We cannot use the #define, after valid C# code has been written. They have to come at the
beginning of the file.
a.cs
#define vijay
class zzz
#if vijay
System.Console.WriteLine("1");
#endif
Output
As a #define creates a variable, its value can be checked by the if or more precisely the #if which
works in the same way as the if of C# does. Thus the #if is true and all code up to the #endif gets
added to the code.
a.cs
class zzz
#if vijay
System.Console.WriteLine("1");
#else
System.Console.WriteLine("2");
#endif
}
Output
The same rules as before for an else. Here as we have not created an identifier called vijay, it gets
a value of false and therefore the #if is false. Imagine a preprocessor identifier as a boolean
variable.
Run the C# compiler as follows on the above program and observe the change in output.
Output
The output displays 1 as the /D compiler option lets you create identifiers at the time of
compiling the program. This cannot be done with a normal variable. We can add/subtract lots of
code form our program, at the time of compilation.
a.cs
#undef vijay
class zzz
#if vijay
System.Console.WriteLine("1");
#else
System.Console.WriteLine("2");
#endif
Output
As we are allowed to create an identifier vijay by the define, the undef does the reverse. It sets it
to false which is the default in any case. As the value of vijay is false, the else gets activated.
However we run the above as csc /D:vijay a.cs, we are first creating an identifier vijay at the
command line prompt, then undefining it at the first line in the program and the output will show
2 as before. You cannot use the define or undefine after real code.
a.cs
#define vijay
#undef vijay
#undef vijay
class zzz
#if vijay
System.Console.WriteLine("1");
#endif
People are allowed to nag you as many times as they like. Repetition has been part of human
history since ancient times. You are allowed to undef as many times as you like even though it
makes no logical sense.
a.cs
#define vijay
#define mukhi
class zzz
#if vijay
#if mukhi
System.Console.WriteLine("1");
#endif
#endif
Output
You can have as many #if's within #if's. We call them nested if's. If the #if is true, then the text up
to the #endif is included.
a.cs
#define vijay
class zzz
{
#if vijay
System.Console.WriteLine("1");
#else
int int;
#endif
We get no error at all in spite of the fact that we are not allowed to create a variable called int. Is
C# sleeping at the wheel? It is not as the preprocessor realized that the identifier vijay is true, it
removed all the code from the #else to the #endif. C# did not flag an error at all, as it was not
allowed to see the offending code by the preprocessor.
a.cs
class zzz
#if vijay
System.Console.WriteLine("1");
#else
int int;
#endif
Compiler Error
Now we see the error as the identifier vijay is false. Remember what the C# compiler sees is
what the preprocessor allows it to. You write code and what the compiler sees may be very very
different.
a.cs
class zzz
Compiler Warning
Whenever we want a warning message to be displayed at the time of compiling our code we use
#warning.
a.cs
class zzz
Compiler Warning
a.cs(3,10): warning CS1030: #warning: 'We have a code red'
Unlike the #define, the #warning can be used anywhere in our program. It enables us to add to
the messages of the compiler. Also the line number changes from 1 to 3 telling us where the
warning occurred.
a.cs
class zzz
Compiler Error
Wherever we have warnings, errors cannot be far behind. The difference is that an error unlike a
warning, stops everything in its tracks and does not let the compiler proceed ahead. No exe file is
created. Normally an error or warning would be placed in an if statement as follows.
a.cs
#define vijay
#define mukhi
class zzz
#endif
public static void Main()
Compiler Error
The && means and. The if is true if both sides of the && is true. They are in this case. Remove
one of the above #defines and the if will be false.
a.cs
class zzz
Compiler Warning
The line directive does two things. One it changes the line number from 1 which is what is
should be at the beginning to 100. Thus the warning appears on line 102 now and not 2. Also the
file name changes from a.cs to vijay. You have total control over the line number and file name
displayed.
a.cs
int int;
char char;
Compiler Error
Line does not only work with the #error or #warning. It affects also the compiler's error line
number and file name. You are allowed to have as many #lines as you prefer.
7
Function Overloading and Inheritance
Its not what you get but what you give that makes you a richer person. Unfortunately, this little
gem is understood only be a few and giving remains largely a one way street.
This chapter explains function overloading, the params parameter and inheritance. We start with
function overloading.
Function Overloading
a.cs
class zzz
a.abc(10);
a.abc("bye");
a.abc("no",100);
class yyy
System.Console.WriteLine("abc" + i);
System.Console.WriteLine("abc" + i);
System.Console.WriteLine("abc" + i + j);
Output
abc10
abcbye
abcno100
The class yyy has three functions, all of them having the same name abc. The distinction
between them is in the data types of the parameters. They are all different. In C# we are allowed
to have functions with the same name, but having different data types parameters. The advantage
is that we call the function by the same name as by passing different parameters, a different
function gets called. This feature is called function overloading. All is fine only if the parameter
types to the function are different. We do not have to remember a large number of functions by
name.
The only reason why function overloading works is that C# does not know a function by name,
but by its signature. A signature denotes the full name of the function. Thus the name of a
function or its signature is the original function name plus the number and data types of its
individual parameters.
a.cs
class zzz
Compiler Error
a.cs(6,12): error CS0111: Class 'zzz' already defines a member called 'abc' with the same
parameter types
Here we have two functions abc which differ only in the values they return. As return values do
not count in the function signature and the function names are similar, hence the error.
a.cs
class zzz
Compiler error
a.cs(6,14): error CS0111: Class 'zzz' already defines a member called 'abc' with the same
parameter types
We have 2 abc's, that accept an int and differ only in the addition of a modifier static. They have
the same signature as modifiers like static are not considered as part of the function signature.
Also, in the next program, we have two abc's with different access modifiers which differ in the
parameters, hence signature/name changes causing an error.
a.cs
class zzz
void abc(int i)
i = 10;
}
Compiler Error
a.cs(10,6): error CS0663: 'abc' cannot define overloaded methods which differ only on ref and
out
The signature consists of not only the parameter data types, but also the kind of parameters i.e.
out ref etc. As function abc takes an int with different modifiers i.e. out etc, the signature on each
is different. The signature of a method consists of its name and number and types of its formal
parameters. The return type of a function is not part of the signature. No two functions can have
the same signature and also non-members cannot have the same name as members.
A function/method can be called by four different types of parameters. These are pass by value,
reference, output and finally parameter arrays. The parameter modifier is not part of the function
signature. Lets now understand what parameter arrays are all about.
Params Parameter
A method declaration creates a separate declaration space. This means that anything created in a
method is lost at the end of the method.
a.cs
string i;
Compiler Error
a.cs(6,8): error CS0136: A local variable named 'i' cannot be declared in this scope because it
would give a different meaning to 'i', which is already used in a 'parent or current' scope to
denote something else
Parameter names have to be unique. Also, we cannot have a parameter and a variable created in a
function block with the same name.
In pass by value, the value of the variable is passed. In the case of ref and out, the address of the
reference is passed.
a.cs
string s = "hi";
{
zzz z = new zzz();
z.pqr();
void pqr()
System.Console.WriteLine(s);
System.Console.WriteLine(s);
a="no";
System.Console.WriteLine(s);
b = "yes";
System.Console.WriteLine(s);
s = "maybe";
Output
hi
no
yes
maybe
You are allowed to pass the same ref parameter as many times as you desire. In the function abc
the string s has a value of hi. Then by changing the string b to no, we are actually changing the
string s to no as s is passed by reference. Variables a and s refer to the same string in memory.
Changing one changes the other. Again changing b also changes s as they refer to the same
string. Thus variables a, b and s refer to the same string in memory.
a.cs
z.pqr();
void pqr()
abc(2,"hi","bye","no");
abc(20,"hi");
abc(2);
foreach ( string s in b)
Output
hi 2
bye 2
no 2
hi 20
We will encounter a situation where we would like to pass a variable number of arguments to a
function. This is not possible as of now as C# is extremely finicky about the number and type of
data we pass to a function. If we pass a string where an int is expected, C# starts screaming like a
baby. If we want to pass a variable number of arguments to a function, we have to use a keyword
params. This keyword can only be applied to the last parameter. Therefore the variable number
of arguments can only come at the end. In the case of function abc, the first parameter has to be
an int, the rest of them can be from zero to an infinite number of strings.
a.cs
Compiler Error
a.cs(6,18): error CS0231: A params or __arglist parameter must be the last parameter in a formal
parameter list
The params keyword in this version has to be at the end only as stated above.
a.cs
z.pqr();
void pqr()
abc(2,3,4);
abc(20,1);
abc(2);
foreach ( int s in b)
Output
32
42
1 20
C# is smart enough if the penultimate parameter and the params have the same data type. The
first int is stored in the variable i, the rest are made part of the array b.
a.cs
Compiler Error
a.cs(6,6): error CS0225: The params parameter must be a single dimensional array
The data type of the params parameter must be, as the error message states, a single dimensional
array. Thus [][] is allowed but not [,]. You are also not allowed to combine the params keyword
with ref or out.
a.cs
z.pqr();
void pqr()
string [] s = {"hi","bye","no"};
abc(2,s);
foreach ( string s in b)
Output
hi 2
bye 2
no 2
You are allowed to pass an array of strings instead of individual strings as parameters. Here s is
an array of strings which has been initialized using the short form. Internally when we call the
function abc, C# converts the array of strings into individual strings.
a.cs
z.pqr();
void pqr()
{
string [] s1 = {"hi","bye"};
abc(2,s1,"hell");
Compiler Error
a.cs(11,1): error CS1502: The best overloaded method match for 'zzz.abc(int, params string[])'
has some invalid arguments
a.cs(11,7): error CS1503: Argument '2': cannot convert from 'string[]' to 'string'
Mixing and matching is not allowed in C#. What we assumed C# would do is to add the last
string hell to the array of strings s1 or convert s1 to individual strings and then add the string hell
to it. Perfectly logical we thought. Only if wishes were horses…
Internally before calling the function abc, it collects all the individual parameters and converts it
into one big array for the params statement.
a.cs
z.pqr();
}
void pqr()
int [] a = {1,2,3};
abc(2,a);
System.Console.WriteLine(a[1]);
b[1] = 100;
Output
100
The output produced is proof of concept. The array member a[1] has an initial value of 2 and in
the function abc we change it to 100. The original changes, this means that the array is given to
the function abc.
a.cs
z.pqr();
}
void pqr()
int a = 10;
abc(2,100,a,20);
System.Console.WriteLine(a);
b[1] = 100;
Output
10
In this case C# creates an array containing 100 10 and 20. We are changing the second member
to 100 which has nothing to do with the variable a. As abc has no knowledge of a, how on earth
can abc change the value of the int a? Thus it stays the same.
a.cs
z.pqr();
}
void pqr()
abc(2);
abc(2,3);
abc(2,3,5,6);
System.Console.WriteLine("params a");
Output
params a
two ints 2 3
params a
Here we are discussing function overloading. C# is extremely bright though partial. It does not
like the params statement and treats it like a stepchild. When we call abc with one int, C# can
only call the abc that takes a params as a parameter as it matches one int. An array can contain
one member. The fun starts with the abc that is being called with two ints. Here we have a
dilemma. C# can call the params abc or the abc with two ints. As mentioned earlier, C# treats the
params as a second class citizen and therefore chooses the abc with two ints. When there are
more than two ints like in the third invocation, C# has no choice but to grudgingly choose the
abc with the params. C# chooses the params as a last resort before flagging an error.
a.cs
using System;
class zzz
foreach (object o in b) {
Console.WriteLine();
object o = a;
ff(a);
ff((object)a);
ff(o);
ff((object[])o);
Output
System.Object[]
System.Object[]
System.Int32 System.String System.Double
In the first case we are passing the function ff an array of object that looks like object. We will
tell you a little later that all classes are derived from object. The function ff receives an array of
objects b. In the foreach we know that the object class has a function GetType that returns an
object that looks like Type, which in turn has a function called FullName which returns the name
of the type. We see three different types displayed. In the second invocation of ff we are casting a
to an object. There is no conversion available from converting an object to an object array i.e.
object []. Therefore a one element object [] is created. It's the same case in the third invocation
and the last explicitly casts to an object array.
a.cs
using System;
class zzz
Console.WriteLine(b.GetType().FullName);
Console.WriteLine(b.Length);
Console.WriteLine(b[0]);
ff((object)a);
Output
System.Object[]
System.Object[]
Inheritance
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
class xxx
{
Compiler Error
a.cs(6,1): error CS0117: 'xxx' does not contain a definition for 'abc'
The class yyy contains 2 functions and one instance variable. The class xxx contains no code and
no variables at all. An empty class does not denote any error as we are able to instantiate an
object that looks like xxx. The error comes about because the class xxx has no function called
abc. However the class yyy has a function abc. Would it not be great if we were allowed to use
all the code in the class yyy from xxx. Easier said than done, we guess!
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
}
public void pqr()
System.Console.WriteLine("yyy pqr");
Output
yyy abc
The error disappears and the abc in yyy gets executed. If after the name of the class you write :
yyy i.e. the name of another class, a lot happens at once. xxx is now said to have been derived
from yyy. What that means is all the code we wrote in yyy can now be used in xxx. It is if we
actually wrote all the code that is contained in yyy in xxx. If we had created an object that looks
like yyy, everything that the object could do, now an object that looks like xxx can also do. But
we have not written a line of code in xxx. We are made to believe that xxx has one variable i and
two functions abc and pqr as yyy contains these two functions. Here we are teaching you the
concepts of inheritance where yyy will now be called the base class, xxx the derived class.
a.cs
class zzz
a.abc();
}
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
Compiler Warning
a.cs(23,13): warning CS0108: The keyword new is required on 'xxx.abc()' because it hides
inherited member 'yyy.abc()'
Output
xxx abc
Nothing in the world stops class xxx from creating a function abc i.e. one with the same name as
in the base class . C# simply gives us a warning. When we run a.abc(), C# first checks whether
the class xxx (as a looks like xxx) has a function called abc. If it does not, then it will check in
the base class. Earlier abc was only available in the base class and hence got executed. Here as it
is already there in xxx, it gets called from xxx and not yyy. Remember the derived classes get a
first shot at execution, then the base class. The reason being, the base class may have a number
of functions and for various reasons you may not be satisfied with what they do. You should have
the right to have your copy of the function to be called. In other words the derived classes
functions override the ones in the base class.
a.cs
class zzz
a.abc();
class yyy
System.Console.WriteLine("yyy abc");
{
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
base.abc();
Output
xxx abc
yyy abc
What if you want the best of both worlds? You may want to call the base classes abc first and
then yours or vice versa. To accomplish this, C# gives you a reserved word, something free
called base. The word base can be used in any derived class. It means call the function off the
base class. Simple. Thus base.abc will call the function abc from yyy the base class of xxx.
a.cs
class zzz
a.abc();
}
class yyy
System.Console.WriteLine("yyy abc");
System.Console.WriteLine("yyy pqr");
System.Console.WriteLine("xxx abc");
base.pqr();
Output
xxx abc
yyy pqr
There is only one small change made to the program and that is base.abc is replaced by base.pqr.
In this case the function pqr from the class yyy gets called. Base is very general purpose. It lets
you access members of the base class from the derived class. You cannot use base in yyy as yyy
is not derived from any class. Thus base can only be used in derived classes.
a.cs
class zzz
a.xyz();
class yyy
System.Console.WriteLine("yyy abc");
Compiler Error
a.cs(6,1): error CS0117: 'yyy' does not contain a definition for 'xyz'
In this case, xxx is derived from yyy and not vice versa. Thus xxx can use all the members of
yyy. Inheritance does not work backwards. Whatever members xxx comprises do not permeate
upwards to yyy. Class xxx may now have a function xyz but it cannot give it to class yyy and
thus an error occurs.
A class inherits everything from its base class except the constructors and destructors. If a class c
is derived from class b, which in turn has been derived from class a, class c inherits all the
members declared in class b and also class a. This concept is called transitive. A derived class
can inherit all the members of the base class but cannot subtract or remove members off that base
class. A derived class can hide members of the base class by creating functions by the same
name. The original member in the base class remains unchanged and unaffected by whatever is
happening in the derived class. It remains unchanged in the base class, it is simply not visible in
the derived class.
A class member can either be a static member belonging to the class or an instance member
belonging to the instance i.e. accessible through the object and not the class. The default is non-
static.
A class is also called a data structure. It consists of data members like constants, fields and
events and function members like methods, properties, indexers, operators, constructors, static
constructors and destructors. A class within a class is called a nested class. Thus we can place 11
different types of entities in a class. Function members are the only members of a class that
contain executable code. A class creation creates a new declaration space.
All classes derive from object . Object is the mother of all classes.
a.cs
{
}
If you do not derive from any class, then the C# compiler automatically adds :object to your class
definition. Object, the only class to have this feature is not derived from any class. It is the
ultimate base class of all classes in the C# hierarchy.
class aa
class bb : aa
Class aa is the base class of bb . The documentation however calls aa the direct base class of bb.
Thus the base classes of bb are aa and object.
a.cs
class aa : System.Delegate
class bb : System.Enum
{
}
class cc : System.Array
class dd : System.ValueType
Compiler Error
a.cs(7,7): error CS0644: 'aa' cannot inherit from special class 'System.Delegate'
a.cs(10,7): error CS0644: 'bb' cannot inherit from special class 'System.Enum'
a.cs(13,7): error CS0644: 'cc' cannot inherit from special class 'System.Array'
a.cs(16,7): error CS0644: 'dd' cannot inherit from special class 'System.ValueType'
You cannot derive a class from the above 4 classes as they are special.
a.cs
class aa
}
class bb
class cc : aa, bb
Compiler Error
A class can only be derived from one more class . You are not permitted to derive from two or
more classes i.e. multiple inheritance is not supported. Thus every class has one and only one
base class.
a.cs
class aa : bb
class bb : cc
}
class cc : aa
Compiler Error
a.cs(13,7): error CS0146: Circular base class definition between 'cc' and 'aa'
class aa is derived from bb. Class bb in turn is derived from cc and cc is derived from aa. This
results in a circular definition. class aa is derived from bb and cc, as bb is derived from cc. As cc
is also derived from aa class, bb also derives from this class which is aa. Thus aa is derived from
aa which is a logical impossibility.
Equating Objects
a.cs
class zzz
a = b;
b = a;
class yyy
}
class xxx {
Compiler Error
C# has a very simple rule. It does not like you to equate different objects to each other. Thus an
object that looks like yyy cannot be equated to one that looks like xxx and vice versa. Thus the
error. Another example - you cannot take an int and equate it to a string . C# is extremely strict
when it comes to dealing with different data types.
a.cs
class zzz
a = b;
b = a;
class yyy
}
class xxx : yyy
Compiler Error
There is however one way out. On account of this way, one of the errors disappeared. The only
time we are allowed to equate dissimilar data types is when we derive from them. Lets explain
this in detail.
When we create an instance of yyy by saying new, we are creating two objects at one go, one
that looks like yyy and the other that looks like object. All classes in C# are finally derived from
object. As xxx is derived from yyy, when we say new xxx, we are creating 3 objects, one that
looks like yyy, one that looks like xxx and finally object.
Thus when we write a = b, b looks like xxx, yyy and object and as a looks like yyy, there is a
match at yyy. Consequence? No error. Even though a and b have the same values, using a we can
only access the members of yyy, even though had we used b we could access xxx also. We have
devalued the potency of a . The error arises at b = a, because the class yyy is less/smaller than the
class xxx . The class xxx has yyy and more. We cannot have a larger class on the right and a
smaller class on the left. a only represents a yyy whereas b expects a xxx which is a xxx and yyy.
The basic rule is that we can only equate dissimilar objects if they are derived from each other.
You can equate an object of a base class to a derived class but not vice versa.
a.cs
class zzz
a = b;
b = (xxx) a;
class yyy
Though we broke a C# rule on equating objects, we did not get an error because of the cast . A ()
is called a cast. Within the brackets we put the name of a class. A cast is the great leveler. When
we write b = a, C# expects the right hand side of the equal to to be a b i.e. a xxx . Instead it finds
a i.e. a yyy . So by applying a cast, we are for the moment converting the yyy object into an xxx.
This strategy satisfies the rules of C# on only equating similar objects. Remember it is only for
the duration of the line that a becomes a xxx and not a yyy.
a.cs
class zzz
a = (yyy) b;
b = (xxx) a;
}
class yyy
class xxx
Compiler Error
Unfortunately casting works only if one of the two classes is derived from the other. You cannot
cast any two objects to each other.
a.cs
class zzz
int i = 10;
char j = 'A';
i = j;
j = i;
}
Compiler Error
We are allowed to convert a char into a int as i = j but not the other way round as j = i.
8
Modifiers
Access Modifiers
Whenever a class is created by us we want to have the ability to decide who can access certain
members of the class. In other words, we would like to restrict access to the members of the
class. The basic rule is that members of a class can freely access each other. There is no way one
can prevent a function of a particular class from executing another function in the same class. By
default though, the same class is allowed complete access but no one else is granted access to the
members of the class. The default access modifier is private.
a.cs
class zzz
yyy.pqr();
class yyy
{
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
abc();
Output
yyy pqr
yyy abc
Pqr is public and hence anyone is allowed to execute it. abc has no access modifier which makes
it private, which is anyway the default. The private modifier has no effect on members of the
same class and hence pqr is allowed to call abc. This concept is called member access.
a.cs
class zzz
yyy.abc();
class yyy
{
static void abc()
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
abc(); } }
Compiler Error
a.cs
class zzz
yyy.abc();
class yyy
{
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
abc();
}}
Compiler Error
We have now introduced one more access modifier, protected, which also does not let you access
a class from outside. However pqr is allowed to access abc as access modifiers do not effect the
same class as mentioned earlier.
a.cs
class zzz
xxx.aaa();
class yyy
{
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
abc();
pqr();
xyz();
Compiler Error
We are now dealing with derived classes. When we flag a function with the modifier, protected,
we are informing C# that only derived classes can access the function. Nobody else can. Thus in
function aaa we can call xyz as it is flagged protected, but it cannot be called from anywhere else
including Main. The function abc is private and can be called only from the class yyy. Comment
out abc(); in aaa and csc will show you no errors.
To sum up, we have learnt three concepts. Private means only the same class has access, public
means everyone has access and protected lies in between where only derived classes have access.
All functions for example reside in a class. The accessibility of that function is decided by the
class in which it resides as well as the modifiers on the function. If we are allowed access to a
member, we say that the member is accessible, else inaccessible.
b.cs
This command will produce a library b.dll with one class yyy.
a.cs
class zzz
yyy a;
Compiler Error
Also writing csc a.cs b.cs would not give us any error.
a.cs
class zzz
Compiler Error
Namespaces by default can have no accessibility modifiers at all. They are public by default and
we cannot add any other access modifier including public again.
a.cs
Compiler Error
b.cs
class yyy
Compiler Error
fatal error CS2022: Options ‘/out’ and ‘/target’ must appear before source file names
Mistake, done on purpose. At times we will forget to tell you that some compiler options like /t
and /out must appear before the names of the source files.
a.cs
class zzz
yyy a;
Compiler Error
Thus if we want other programs/files to access classes created by us, we must not forget that by
default they are marked as internal as explained earlier.
Members of a class can have all the modifiers described above and default to private.
a.cs
class zzz
Compiler Error
You are not allowed more than one access modifier most of the time. The exceptions, we will
soon take care off. Predefined types like int, object have no accessibility restrictions. They can be
used anywhere and everywhere.
b.cs
class yyy
class zzz
a.abc();
Compiler Error
a.cs(6,1): error CS0246: The type or namespace name 'a' could not be found (are you missing a
using directive or an assembly reference?)
As the class yyy has not been specified by an access modifier, it is by default internal. Even
though abc is public, the type enclosing it i.e. yyy is internal and hence no member of yyy can be
accessed from outside b.cs. Thus the access modifiers of the class and the members is important.
b.cs
void abc()
a.cs
class zzz
a.abc();
Compiler Error
Here yyy is accessible as the modifier is public but the function abc is private and hence cannot
be accessed by anyone but the class.
From now on we will only display a.cs and b.cs as the command line executions of the compiler
will remain the same. a.cs remains the same for this program.
b.cs
Compiler Error
Internal means no one from outside the dll can access the function.
a.cs
class zzz
a.aaa();
b.cs
void pqr()
abc();
a.abc();
No error occurs as protected internal means two things. It is either derived classes or classes in
the same file that can access abc. Therefore derived class xxx can use it as well as class ppp.
What we are trying to get at here is that the containing type decides first the accessibility and
then the member modifiers also comes in. Making the class internal and then the members public
will in no way allow classes in others files access it.
a.cs
class zzz
class yyy
protected int x;
a.x = 1;
b.x = 2;
a.x = 1;
b.x = 2;
}}
Compiler Error
a.cs(20,1): error CS1540: Cannot access protected member ‘yyy.x’ via a qualifier of type ‘yyy’;
the qualifier must be of type ‘xxx’ (or derived from it)
Class yyy contains a protected member x. To the same class no modifiers make sense. However
as x is protected, in the derived class function pqr, we cannot access it through yyy as a.x gives
us an error. However b which looks like xxx does not give an error. To check this out, comment
out the line a.x=1 in pqr(). This means that we can access the protected members not from an
object of the base class, but from the derived class objects only. This is in spite of the fact that x
is a member of yyy, the base class. Even so, we still cannot access it. Also we cannot access x
from the function Main.
a.cs
class zzz
}
class yyy
Compiler Error
a.cs(10,14): error CS0060: Inconsistent accessibility: base class ‘yyy’ is less accessible than class
‘xxx’
Between internal and public, public allows greater access to its members. The class yyy is by
default internal and xxx which derives from yyy is explicitly made public. We get an error as the
derived class yyy has to have an access modifier which allows greater access than the base class
access modifier. Here internal is more restrictive than public.
a.cs
class zzz
{
}
If we reverse the modifiers, i.e. we make yyy public and xxx the derived class internal we get no
error. The base class allows more accessibility than the derived class.
a.cs
class zzz
class yyy
Compiler Error
a.cs(12,12): error CS0050: Inconsistent accessibility: return type ‘yyy’ is less accessible than
method ‘xxx.f()’
The accessibility of yyy is internal which is more restrictive than public. The accessibility of
function f is public which is more than that of the type yyy. The error occurred as return values
must have greater accessibility than that of the method, which is not true in this case.
a.cs
class zzz
class yyy
public yyy a;
Compiler Error
a.cs(12,12): error CS0052: Inconsistent accessibility: field type ‘yyy’ is less accessible than field
‘xxx.a’
Rules are rules – they remain the same everywhere. The class yyy or data type yyy is internal. a,
an object/field is public which makes it more accessible than yyy which is internal. Hence the
error.
a.cs
class zzz
{
public static void Main()
class yyy
yyy a;
Now we get no error as a has been made private which gives it a lower accessibility than yyy
which is internal. Logic is that whatever you create must be more accessible than what you
create from.
Sealed Classes
Sealed is another modifier that applies to classes. aaa is a sealed class. No class can derive from
aaa. In another words aaa cannot act as a base class for any class.
a.cs
Compiler Error
a.cs(10,7): error CS0509: ‘bbb’ : cannot inherit from sealed class ‘aaa’
a.cs
System.Console.WriteLine(a.i);
a.abc();
public int i = 9;
System.Console.WriteLine(“hi”);
}
Output
hi
The only difference between a sealed class and a non-sealed class is that a sealed class cannot be
derived from. Otherwise there is no difference at all. It can contain the same variables, functions
etc as a normal class does . A sealed class lets us create classes which no one can derive from.
Thus the code in such classes cannot be overridden. Also as the compiler knows this, certain run
time optimizations can be performed on a sealed class
Constants
a.cs
System.Console.WriteLine(i);
Output
10
A constant or const variable behaves as a variable. We give it an initial value and can use it
wherever we can use a variable.
a.cs
{
const int i = 10;
i++;
System.Console.WriteLine(i);
i = 30;
Compiler Error
a.cs(6,1): error CS0131: The left-hand side of an assignment must be a variable, property or
indexer
a.cs(8,1): error CS0131: The left-hand side of an assignment must be a variable, property or
indexer
Unlike a variable, we are not allowed to change the value of a const. The change is an
assignment statement.
a.cs
const int i ;
i = 30;
System.Console.WriteLine(i);
}
Compiler Error
We have to initialize the const variable at the time of creation. We are not allowed to initialize it
later in our program.
a.cs
const int i = j + 4;
const int j = k - 1;
const int k = 3;
Output
623
A constant can depend upon another constant. C# is smart enough to realize that to calculate the
value of const i, it first needs to know the value of j. j’s value depends upon another const k,
whose value is 3. Thus C# first evaluates k to 3 then j becomes 2 i.e. k -1 and finally i takes on
the value of j i.e. 2 + 4 resulting in 6.
Like classes const’s cannot be circular i.e., they cannot depend upon each other.
a.cs
{
const int i = j + 4;
const int j = k - 1;
const int k = i;
Compiler Error
a.cs(3,11): error CS0110: The evaluation of the constant value for ‘zzz.i’ involves a circular
definition
The value of the const i depends upon j which in turn depends upon k, which is equal to i. This
becomes a circular definition. A const is a variable whose value cannot be changed but whose
initial value is compile time determined.
a.cs
public class aa
}
Compiler Error
a.cs(3,17): error CS0133: The expression being assigned to ‘zzz.a’ must be constant
a.cs
public class aa
The error vanishes as we are now initializing a to an object which has a value that can be
determined at compile time. We cannot ever change the value of a, so it will always be null.
Normally we do not have consts as a reference type as they have value only at runtime.
As mentioned earlier we can only initialize a const to a compile time value i.e. a value available
to the compiler while it is executing. new unfortunately gets executed at runtime and therefore
has no value at compile time. This gives us an error.
a.cs
class zzz
class yyy {
Compiler Error
a.cs(6,26): error CS0176: Static member 'yyy.i' cannot be accessed with an instance reference;
qualify it with a type name instead
A constant is static by default and we cannot use the instance reference i.e. a name to reference a
const. A const has to be static as no one is allowed to make any changes to a const.
a.cs
class zzz
class yyy
Compiler Error
a.cs
class zzz
System.Console.WriteLine(yyy.i + “ “ + xxx.i);
class yyy
Compiler Warning
a.cs(14,18): warning CS0108: The keyword new is required on ‘xxx.i’ because it hides inherited
member ‘yyy.i’
Output
3 30
We can create a const with the same name as another const in the base class. The const of the
class xxx i will hide the const i in class yyy for the class xxx only.
Fields
A field to start with is another word for a variable in a class. There are a large number of generic
rules that apply to all members of a class and we will not tire you by repeating them ad nauseam.
a.cs
static int i;
static bool j;
System.Console.WriteLine(zzz.i + “ “ + zzz.j );
}}
Output
0 False
Static variables are initialized when the class is loaded first. An int is given an initial value of
zero and a bool False.
a.cs
int i;
bool j;
{
zzz a = new zzz();
System.Console.WriteLine(a.i + “ “ + a.j );
}}
Output
0 False
An instance variable is initialized at the time of creation. The keyword new will create an
instance of the zzz. It will allocate memory for each of the non static variables and then initialize
each of them to their default values.
a.cs
static int j = i + 1;
System.Console.WriteLine(zzz.i + “ “ + zzz.j );
Output
10 11
Outputs make a lot of sense if you understand them in plain simple English. C# always initializes
static fields to their initial value after creating them . Variables i and j are thus given a default of
zero. Then C# realizes that these variables need to be assigned some values. It does not read all
the lines, only one at a time. It will now read the first line and as the variable j has a value of 0, i
will get a value of 10. Then at the next line, j is the value of i plus 1. The variable i has a value of
10 and j now becomes 11. As it does not see both lines at the same time, it does not notice the
circularity of the above definition. In short, though the above example works, it is frowned upon
by the powers to be at C#.
a.cs
int i = j + 10;
int j = i + 1;
Compiler Error
a.cs(3,9): error CS0236: A field initializer cannot reference the nonstatic field, method, or
property ‘zzz.j’
a.cs(4,9): error CS0236: A field initializer cannot reference the nonstatic field, method, or
property ‘zzz.i’
It does not work for instance variables as the rules of an instance variable are different than that
of static. The field initializer of an instance variable has to be determined at the time of creation
of the object. The variable j does not have a value at this point in time. It cannot refer to variables
of the same instance at the time of creation. Thus we can refer to no instance members to
initialize an instance member. Textual order means first come first served.
Readonly Fields
a.cs
System.Console.WriteLine(i);
Output
10
No errors at all. However, remember if we use a non static variable in a static function we will
get an error.
a.cs
i = 20;
System.Console.WriteLine(i);
Compiler Error
a.cs(6,1): error CS0198: A static readonly field cannot be assigned to (except in a static
constructor or a variable initializer)
You cannot change the value of a readonly field after its being given an initial value.
a.cs
Unlike a const, a readonly field does not have to be initialized at the time of creation.
a.cs
static zzz()
i = 20;
System.Console.WriteLine(“In Const”);
System.Console.WriteLine(i);
Output
In Const
20
A static readonly field can be initialized in a static constructor also. This is the major difference
between a const and a readonly field.
a.cs
public class aa
The same example which gave an error with const does not give an error with readonly. To sum
up a readonly is a more generic const and it makes our programs more readable as we refer to a
name and not a number. Is 100 more intuitive or priceofcopper easier to understand? The
compiler would for reasons of efficiency convert all const’s and readonly variables to the actual
values.
a.cs
public class aa
{
public int readonly i = 10;
Compiler Error
a.cs(9,12): error CS1585: Member modifier ‘readonly’ must precede the member type and name
a.cs(9,23): error CS1519: Invalid token ‘=’ in class, struct, or interface member declaration
Wherever you can place multiple modifiers, remind yourself that there are rules that decide the
order of modifiers, which comes first. Here the readonly modifier precedes the data type int.
Once again, no great cosmic law responsible, just a rule that must be remembered.
a.cs
public class aa {
void pqr()
abc(ref i);
}
}
Compiler Error
a.cs(13,9): error CS0192: A readonly field cannot be passed ref or out (except in a constructor)
A readonly field cannot be changed by anyone except a constructor. The function abc expects a
ref parameter which if you have forgotten allows you to change the value of the original. Thus
C# does not permit a readonly as a parameter to a function that accepts a ref or a out parameters.
9
Virtual Functions - new and
override
Every breath you take,
a.cs
class zzz
a.abc();a.pqr();a.xyz();
b.abc();b.pqr();b.xyz();
c.abc();c.pqr();c.xyz();
class yyy
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
{
System.Console.WriteLine(“xxx abc”);
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“xxx xyz”);
Compiler Warning
a.cs(30,13): warning CS0108: The keyword new is required on 'xxx.abc()' because it hides
inherited member 'yyy.abc()'
a.cs(34,13): warning CS0108: The keyword new is required on 'xxx.pqr()' because it hides
inherited member 'yyy.pqr()'
a.cs(38,13): warning CS0108: The keyword new is required on 'xxx.xyz()' because it hides
inherited member 'yyy.xyz()'
Output
yyy abc
yyy pqr
yyy xyz
xxx abc
xxx pqr
xxx xyz
yyy abc
yyy pqr
yyy xyz
Class xxx derives from class yyy. That makes xxx the derived class and yyy the base class. The
class xxx comprises yyy and more. Thus can we not conclude, albeit in broken English that an
object that looks like xxx is bigger than one that looks like yyy. In C#, you can equate a smaller
object to a bigger object as stated earlier.
Lets take the case of object a. It looks like yyy and initialized by creating an object that also
looks like yyy. When we call the functions abc and pqr and xyz through the object a obviously it
will call them from yyy.
Object b looks like xxx, the derived class. It is initialized to an object that looks like xxx. When
we call abc, pqr and xyz through b, it calls abc, pqr and xyz from xxx.
Object c again looks like yyy but it is now initialized to an object that looks like xxx which does
not give an error as explained earlier. However there is no change at all in the output and the
behavior is identical to that of object a. Hence initializing it to an object that looks like yyy or
xxx does not seem to matter.
a.cs
class zzz
a.abc();a.pqr();a.xyz();
b.abc();b.pqr();b.xyz();
c.abc();c.pqr();c.xyz();
}
}
class yyy
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
System.Console.WriteLine(“xxx abc”);
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“xxx xyz”);
Compiler Error
a.cs(30,22): error CS0506: ‘xxx.abc()’ : cannot override inherited member ‘yyy.abc()’ because it
is not marked virtual, abstract, or override
We get an error because we have added two new modifiers, new and override to the functions.
The error says to add the modifier virtual to the functions in the base class.
a.cs
class zzz
a.abc();a.pqr();a.xyz();
b.abc();b.pqr();b.xyz();
c.abc();c.pqr();c.xyz();
}
class yyy
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
System.Console.WriteLine(“xxx abc”);
}
public new void pqr()
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“xxx xyz”);
Output
yyy abc
yyy pqr
yyy xyz
xxx abc
xxx pqr
xxx xyz
xxx abc
yyy pqr
yyy xyz
There is a single subtle change in the workings of the objects c only and not a and b. Adding the
virtual modifier has made all the difference. The difference is in the object c. c looks like the
base class yyy but is initialized to an object that looks like the derived class xxx. C# remembers
this fact. When we execute c.abc(), C# remembers that object c was initialized by a xxx object
and hence it first goes to class xxx. Here the function has a modifier override which in English
means, forget about the data type of c which is yyy, call abc from xxx as it overrides the abc of
the base class. The override modifier is needed as the derived class functions will get first
priority and be called. We mean to override the abc of the base class. We are telling C# that this
abc is similar to the abc of the base class.
New has the exactly the opposite meaning. The function pqr has the new modifier. C.pqr() calls
pqr from yyy and not xxx. New means that the function pqr is a new function and it has
absolutely nothing to do with the pqr in the base class. It may have the same name pqr as in the
base class, but that is only a coincidence. As c looks like yyy, the pqr of yyy gets called even
though there is a pqr in xxx. When we do not write any modifier, then it is assumed that we
wrote new. Thus every time we write a function, C# assumes it has nothing to do with the base
class. These modifiers can only be used if the function in the base class is a virtual function. To
us virtual means that the base class is granting us permission to call the function from the derived
class and not the base class. We have however one caveat, we have to add the modifier override
if our derived class function has to be called.
a.cs
class zzz
a.abc();a.pqr();a.xyz();
b.abc();b.pqr();b.xyz();
c.abc();c.pqr();c.xyz();
class yyy
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
System.Console.WriteLine(“xxx abc”);
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“xxx xyz”);
System.Console.WriteLine(“vvv abc”);
System.Console.WriteLine(“vvv xyz”);
Output
yyy abc
yyy pqr
xxx xyz
yyy abc
yyy pqr
xxx xyz
vvv abc
xxx pqr
xxx xyz
Pretty long example. To reiterate, we are allowed to initialize a base object to a derived object.
The other way around will generate an error. This leads to an object of a base class being
initialized to an object of the derived class. The question that now springs to mind is, which
function will get called. The one from the base class or the derived class. If the base class object
declared the function virtual and the derived class used the modifier override, the derived class
function will get called. Otherwise the base class function will get executed. Thus for virtual
functions, the data type created is decided at run time. All functions not tagged with virtual are
non virtual, and the function to be called is decided at compile time, depending upon the static
data type of the object. If the object is initialized to the same data type, none of the above apply.
Whenever we have a mismatch, we need rules to resolve the mismatch. Thus we can land up
with a situation where an object to a base class can call a function in the derived class.
The object a looks like yyy but is initialized to the derived class xxx. a.abc(), first looks into the
class yyy. Here it checks whether the function abc is virtual. The answer is an emphatic no and
hence everything stops and the function abc gets called from class yyy. a.pqr does the same
thing, but the function now is virtual in class yyy. Thus C# looks at the class yyy, the one it was
initialized to. Here pqr is flagged with the modifier new. This means that pqr is a new function
which has nothing to do with the one in the base class. They only accidentally share the same
name. Thus as there is no function called pqr (as it is a new pqr) in the derived class, the one
from base class gets called. In the case of a.xyz(), the same steps are followed again, but in the
class yyy, we meet the modifier override, which overrides the function in the base class. We are
telling C# to call this function in class xxx and not the one in the base class yyy.
The object b which also looks like class yyy, is now initialized with an object that looks like vvv
and not xxx like before. As abc is non virtual it gets called from yyy. In the case of function pqr,
C# now looks into class vvv. Here it sees no function pqr and hence now looks into class xxx.
Thus the above rules repeat and it gets called from class yyy. In the case of b.xyz, in class vvv, it
is marked new by default and hence this function has nothing to do with the one in class yyy.
Hence the one from vvv does not get called but the one from class yyy where it specifies
override.
System.Console.WriteLine(“vvv xyz”);
If we change xyz in class vvv to the above, i.e. we change new to override, the xyz of vvv will
get called.
The last object c looks like xxx but is now initialized to an object that looks like the derived class
vvv. c.abc(), first looks into class xxx where it is marked as virtual. Remember abc is non virtual
in class yyy but virtual in xxx. From now on, the function abc is virtual in vvv also but not in
class yyy. Virtual is like water, it flows downwards not upwards. As abc is virtual, we now look
into class vvv. Here it is marked override and hence abc gets called from class vvv. In the case of
pqr, pqr is marked virtual in class yyy and new in xxx, but as there is no function pqr in vvv,
none of the modifiers matter at all. Thus it gets called from class xxx. Lastly for function xyz, in
class vvv it is marked new. Hence it has no connection with the xyz in class xxx and thus
function xyz gets called from xxx and not yyy.
a.cs
class zzz
class yyy
Compiler Error
a.cs(17,22): error CS0506: ‘vvv.pqr()’ : cannot override inherited member ‘xxx.pqr()’ because it
is not marked virtual, abstract, or override
We get an error as the function pqr in class xxx is marked new. This means that it hides the pqr of
class yyy. Form the viewpoint of class vvv, xxx does not supply a function called pqr. The pqr in
class xxx has nothing to do with the pqr in yyy. This means that the function pqr of xxx does not
inherit the virtual modifier from the function pqr of class yyy. This is what the compiler is
complaining about. As the function pqr in xxx has no virtual modifier, in vvv we cannot use the
modifier override. You can, however, use the modifier new and remove the warning.
a.cs
class zzz
a.pqr();
b.pqr();
class yyy
System.Console.WriteLine(“yyy pqr”);
}
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“vvv pqr”);
Output
yyy pqr
vvv pqr
System.Console.WriteLine(“vvv pqr”);
}
Output
yyy pqr
xxx pqr
That’s the problem with virtual functions. We call them the cause of migraine. The answers are
always different from what you expect. Object a looks like a yyy but is initialized to the derived
class vvv. As pqr is virtual, C# now looks into class vvv. However before looking into the class,
it realizes that in class xxx, pqr is new. This cuts of all connection with the pqr in yyy. Thus the
word new is preceded with virtual, otherwise the override modifier would give us an error in
class vvv. As pqr in class xxx is new function, having nothing to do with the class yyy, class vvv
inherits a new which also has nothing to do with the class yyy. The pqr in class vvv is related to
the pqr of class xxx and not of class yyy. Thus the pqr of class yyy gets called.
In the second case object b looks like class xxx now but is initialized to an object of class vvv.
C# first looks at class xxx. Here pqr is new and virtual, which makes it a unique function pqr.
Unfortunately, the pqr in vvv has the override modifier which sees to it that the pqr of vvv hides
the pqr of xxx. This calls the pqr of vvv instead. If we remove the override modifier from pqr in
class vvv, the default is new, that cuts off the umbilical cord from the pqr of xxx. Thus, as it is, a
new function, the pqr of xxx gets called.
A virtual function cannot be marked by the modifiers static, abstract or override. A non virtual
function is said to be invariant. This means that the same function gets called always, irrespective
of whether one exists in the base class or derived class. In a virtual function the run-time type of
the instance decides on which function to be called and not the compile-time type as is in the
case of non virtual functions. For a virtual function there exists a most derived implementation
which gets always gets called.
a.cs
class zzz
a.pqr();b.pqr();c.pqr();d.pqr();
class yyy
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“www pqr”);
}
System.Console.WriteLine(“vvv pqr”);
Output
xxx pqr
xxx pqr
vvv pqr
vvv pqr
One last explanation of virtual with a slightly more complex example involving 4 classes.
The first line in Output, xxx pqr, is the result of the statement a.pqr();. We have the function pqr
as virtual in class yyy. Hence, when using new, we now proceed to class xxx and not vvv as
explained earlier. Here, pqr has an override and C# knows that class www inherits this function
pqr. In class www, as it is marked as new, C# will now backtrack and not proceed further to class
vvv. Hence the function pqr gets called from class xxx as shown in the output.
System.Console.WriteLine(“www pqr”);
}
If we change the function pqr in class www to override, then C# will proceed to class vvv and
call the pqr of class vvv as it overrides the pqr of www. Remove the override from pqr in class
vvv and the function will get called from class www as the default is new.
For object b, everything remains the same as object a, because it overrides the pqr of class yyy.
Restoring back the defaults, lets look at the third line. Object c looks like www. In class www,
pqr is a new and hence it has nothing to do with the earlier pqr functions. In class vvv, we are
overriding the pqr of class www and hence the pqr of vvv gets called. Remove the override and
then it will get called from class www. The object d thankfully follows none of the above rules as
the left and the right of the equal to sign are the same data types.
An override method is a method that has the override modifier included on it. This introduces a
new implementation of a method. You cannot use the modifiers new, static or virtual along with
override. However abstract is permitted.
a.cs
class zzz
a.pqr();
b.pqr();
class yyy
{
System.Console.WriteLine(“yyy pqr”);
base.pqr();
System.Console.WriteLine(“xxx pqr”);
base.pqr();
System.Console.WriteLine(“www pqr”);
Output
yyy pqr
xxx pqr
yyy pqr
xxx pqr
www pqr
Using the keyword base, we can access the base class functions. Here whether pqr is virtual or
not, it is treated as non virtual by the keyword base. Thus the base class pqr will always be
called. The object a knows that pqr is virtual. When it goes to yyy, it sees base.abc and hence it
calls the pqr of yyy. In the second case, it first goes to class vvv, here it calls the base.abc, i.e. the
function pqr of class xxx, which in turn calls function pqr in class yyy.
a.cs
class zzz
a.pqr();
class yyy
System.Console.WriteLine(“yyy pqr”);
{
public override void pqr()
((yyy)this).pqr();
System.Console.WriteLine(“xxx pqr”);
Output
No amount of casting will stop the infinite loop. Thus even though this is being cast to a yyy, it
will always call pqr from xxx and not yyy. Hence you see no output
a.cs
class zzz
a.pqr();a.xyz();
b.pqr();b.xyz();
class yyy
System.Console.WriteLine(“yyy pqr”);
System.Console.WriteLine(“yyy xyz”);
System.Console.WriteLine(“xxx pqr”);
System.Console.WriteLine(“xxx xyz”);
{
System.Console.WriteLine(“www pqr”);
System.Console.WriteLine(“www xyz”);
Output
www pqr
yyy xyz
www pqr
xxx xyz
More virtual functions, more complications in life. Let us embark on a thousand mile journey
with a single step.
When we have a statement a.pqr, C# starts at the class yyy as usual, sees virtual, then goes to
class xxx. Here pqr is private and hence its scope is limited to class xxx. The modifier new is
thus ignored. C# now goes to class www where the pqr overrides the pqr of class yyy and thus
we see www pqr. If we remove the override modifier from function pqr in class www, as it is a
new function, it will now be called from class yyy. a.xyz calls pqr from yyy due to the
explanation given many times before i.e. they are all news.
b.pqr knows that pqr in class xxx is private. The scope of this pqr does not extend to class www,
the derived class. As the pqr in class www overrides the pqr of class xxx, the one from class
www gets called as it overrides the one from the base class yyy. If you change the override to
new, then the pqr in www is a new one and has nothing to do with the one from yyy. This calls
pqr from the base class yyy.
b.xyz calls it from class xxx. This has already been explained at least a trillion times earlier.
Abstract Classes
a.cs
new aaa();
Compiler Error
a.cs(5,1): error CS0144: Cannot create an instance of the abstract class or interface ‘aaa’
The keyword abstract can be written before a class. It is called a class modifier. An abstract class
cannot be instantiated by the keyword new. We cannot create an object that looks like aaa. Thus
we cannot use the class and for all practical purposes the class is useless to us.
a.cs
new aaa();
public int i;
public void abc()
The error remains the same. Since we have used the modifier abstract in front of the class we
cannot use new. Had we removed the modifier abstract, all would be fine. This program is to
show that an abstract class can contain variables and functions.
a.cs
new bbb();
public int i;
{
}
We can derive a class bbb from an abstractc class aaa. Thus creating an object that looks like bbb
does not give us any error. We cannot yet use aaa directly.
a.cs
new bbb();
public int i;
Compiler Error
a.cs(10,13): error CS0501: ‘aaa.pqr()’ must declare a body because it is not marked abstract or
extern
In a abstract class we have added a function prototype. An extern or abstract function implies
that the actual definition or code is created somewhere else. A function prototype in a abstract
class must also be declared abstract as per the rules of C#.
a.cs
new bbb();
public int i;
Compiler Error
a.cs(16,7): error CS0534: ‘bbb’ does not implement inherited abstract member ‘aaa.pqr()’
After declaring pqr abstract in aaa, we get another error. We are not allowed to create objects that
look like bbb because it is derived from aaa, an abstract class which has one abstract function.
We have to implement this abstract function pqr in bbb .
a.cs
new bbb();
public int i;
{
}
Compiler Warning
a.cs(18,13): warning CS0114: ‘bbb.pqr()’ hides inherited member ‘aaa.pqr()’. To make the
current method override that implementation, add the override keyword. Otherwise add the new
keyword.
Compiler Error
a.cs(16,7): error CS0534: ‘bbb’ does not implement inherited abstract member ‘aaa.pqr()’
Now we are really lost. The error clearly says that both classes aaa and bbb have a similar
function called pqr. Whenever a class (bbb) derives from another class (aaa) and they both have a
function with the same name, an error results. The only way out is for the derived class bbb to
explicitly add a keyword override to the function definition. This tells the compiler that we know
that the base class has a function of the same name and we want the pqr of bbb to be called, not
aaa’s . It is more of a caution exercised by the compiler so that you do not inadvertently override
functions of the base class. C# has a large number of such cautions that make you think.
a.cs
new bbb();
public int i;
public void abc()
a.cs
new bbb();
public int i;
public void abc()
Compiler Error
a.cs(18,21): error CS0508: ‘bbb.pqr()’: cannot change return type when overriding inherited
member ‘aaa.pqr()’
When you are overriding an abstract function from a derived class, you cannot change the
parameters passed to it or the return type. If the abstract class has 5 functions, the class derived
from it should also implement the same 5 functions without changing return type and/or
parameters passed to it.
a.cs
new bbb();
}
abstract class aaa
public int i;
Compiler Error
a.cs(18,7): error CS0534: ‘bbb’ does not implement inherited abstract member ‘aaa.pqr1()’
a.cs(18,7): error CS0534: ‘bbb’ does not implement inherited abstract member ‘aaa.pqr2()’
The error goes away if we implement functions pqr1 and pqr2 in bbb.
An abstract class implies that the class is incomplete and cannot be directly used. It can only be
used as a base class for other classes to derive from. Hence we get a error if we use new on an
abstract class. If we do not initialize a variable in an abstract class, it will have a value of 0 which
is what the compiler kept warning us about. We can initialize i to any value we want. The
variables have the same use and meaning in an abstract class like any other class. Whenever a
class is incomplete i.e. we do not have the code for certain functions, we make those functions
abstract and the class abstract . This enables us to compile the class without errors. Other classes
can then derive from our incomplete class but they have to implement the abstract i.e. our
incomplete functions. Abstract thus enables us to write code for part of the class and allows the
others to complete the rest of the code.
a.cs
class aaa
Compiler Error
a.cs(9,22): error CS0513: ‘aaa.pqr()’ is abstract but it is contained in nonabstract class ‘aaa’
If a class has even one abstract function, then the class has to be declared abstract. An abstract
method cannot also use the modifiers static or virtual.
Only in the abstract class can we have one abstract function. Anyone who implements from an
abstract class has to write the code for its function. By default the modifier new gets added,
which makes it a new/different function.
a.cs
class zzz
base.abc();
Compiler Error
Like the Sting number, C# is always watching every step you take and every move you make.
Like a hawk. You cannot call the function abc from the base class as it does not carry any code
along with it and has been declared abstract. Common sense prevails and C# does not allow you
to call a function that has no code.
a.cs
class zzz
a.abc();b.abc();
class yyy
System.Console.WriteLine(“yyy abc”);
System.Console.WriteLine(“www abc”);
Output
yyy abc
www abc
a.abc() will first peek into the class yyy. Here it finds function abc tagged as virtual. How many
times have we repeated the above lines? Countless times. C# will then toddle over to class xxx.
Here it finds to its dismay that the function abc is abstract i.e. there is no code for abc and also
that it is a new function, thus severing all links with the base class. Activity stops and all hell
breaks loose and the function abc from yyy gets executed. In the case of b.abc(), as the function
is new, the links to the base class are broken, we have no choice but to call the function from
www as it says override. We cannot replace the modifier new with the keyword override for
function abc in abstract class xxx .
Compiler Error
a.cs(21,7): error CS0534: ‘www’ does not implement inherited abstract member ‘xxx.abc()’
If we replace the override keyword with new in class www, we will get an error as there is no
code for the function abc. Remember the abc of yyy has nothing to do at all with that of xxx and
www.
Virtual functions run slower than non virtual functions and it is obvious that an abstract class
cannot be sealed.
a.cs
}
}
Compiler Error
Properties are a natural extension to fields. Very few programming languages support the notion
of a property. Unlike a variable, a property is not stored in a memory location. It is made up of
functions. Thus even though a property and a field share the same syntax a property has the
advantage that code gets called. When we initialize a variable, no code in our class gets called.
We are not able to execute any code for a variable access or initialization at all. In the case of a
property, we can execute tons of code. This is one singular reason for the popularity of a product
like Visual Basic - the use of properties. One simple example is setting the value of a variable. If
it is through a variable, we have no control over the value used. If the same access is through a
property, the programmer has no inkling of whether it is a property or a variable, we can build
range checks to make sure that the variable does not cross certain bounds.
Lets start by creating a simple property. A property is a member of a class. It behaves like a
variable for the user.
a.cs
public class aa
public int ff {
}
Compiler Error
a.cs(9,12): error CS0548: ‘aa.ff’ : property or indexer must have at least one accessor
We have tried to create a property called ff which is of type int. We get an error because a
property is used either on the left or the right of an equal to sign. If we had created a variable ff,
we would like to write a statement as gg = ff + 9. Here ff should return some value which is of
the data type int.
a.cs
aa a = new aa();
int gg = a.ff + 9;
System.Console.WriteLine(gg);
public class aa
public int ff {
get
System.Console.WriteLine(“in get”);
return 12;
Output
in get
21
A property should have at least one accessor, in our case, a get as we want to read the value of
the property. Thus a.ff calls the get accessor which returns an int, in this case 12. If we did not
have access to the code of the class aa, we would have assumed ff to have been a variable.
a.cs
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
public int ff {
get
{
System.Console.WriteLine(“in get”);
return 12;
set
System.Console.WriteLine(value);
Output
19
in get
12
A variable can also be used on the left-hand side of the equalto sign. In this case we are writing
or changing the value of the variable. We are passing it some value. If it is a property, ff in our
case, a.ff = 19 will call the accessor set. The set accessor has a free variable available in it called
value. It gets created automatically, we do not create this variable. In our case, this has the value
19, which we are displaying in WriteLine. Then to display the value of the property ff, the get
needs to be called again. The get always returns the same answer as the set does not store the
value of the variable anywhere. To resolve this issue, we do the following.
a.cs
{
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
int f1;
public int ff {
get
System.Console.WriteLine(“in get”);
return f1;
set
f1 = value;
Output
in set 19
in get
19
To implement a property in real life, we create a public variable which will hold the value of the
property. This variable f1 will have the same data type as the property i.e. an int in our case. In
the get, we return f1 and in the set we initialize f1 to value. This is the simplest case possible.
The reason we use a property and not a variable is because if we change the value of a
variable/field, then code in our class is not aware of the change. Also we have no control over
what values the variable will contain. The user can change them to whatever he/she likes and we
cannot implement range checks on the variable. Also the user may want to associate some action
with the changes in the value of the variable. Using a property, reading or writing to the variable
also can be monitored.
a.cs
aa a = new aa();
a.ff = 19;
System.Console.WriteLine(a.ff);
public class aa
int f1;
public int ff {
get
{
System.Console.WriteLine(“in get”);
return f1;
Compiler Error
a.cs(6,1): error CS0200: Property or indexer ‘aa.ff’ cannot be assigned to — it is read only
You are allowed to declare a property readonly by omitting the set accessor. No one is now
allowed to change the value of the property. It now behaves as a const or readonly field.
a.cs
aa a = new aa();
a.ff = 19;
public class aa
int f1;
public int ff {
set
{
System.Console.WriteLine(“in set “ + value);
f1 = value;
Output
in set 19
Theoretically, you can have a property which is write only i.e. only with a set accessor. With set,
you can change the value of ff but it is of limited use because you can never access the value of
ff. A property differs from a field by ending with {}.
a.cs
public class aa
public int ff {
set
}
public int ff {
get
Compiler Error
a.cs(12,12): error CS0102: The class ‘aa’ already contains a definition for ‘ff’
You cannot create a property in 2 separate bits and pieces. It has to be in one whole. This is part
of the syntax. The above creates two properties, both called ff, the first one being write only, the
second, read only. The compiler tells you that you cannot create two properties by the same
name.
a.cs
public class aa
public int ff {
get {
}
set {
Compiler Error
a.cs(10,12): error CS0102: The class ‘aa’ already contains a definition for ‘ff’
You obviously cannot have a property and variable with the same name. The compiler would not
know whether to invoke the property or the field. They both are stored in the same namespace.
a.cs
class zzz
yyy.i = 20;
System.Console.WriteLine(yyy.i);
class yyy
get {
System.Console.WriteLine(“get”);
return 10;
}
set {
System.Console.WriteLine(“set “ + value);
Output
set 20
get
10
The rules of static apply to properties also. Like variable we access them using the class and not
the instance. Everything that we have learned about static in the past applies to properties also.
a.cs
class zzz
a.i = 100;
System.Console.WriteLine(a.i);
{
public abstract int i
get ;
set ;
get
System.Console.WriteLine(“get”);
return 10;
set
System.Console.WriteLine(“set “ + value);
Output
set 100
get
10
The abstract property i in class xxx carries no code at all. The get and set accessors are simply
represented by a semicolon. In the derived class, we must implement both the get and the set
accessors. If we do not use the override keyword, it is new. We hope you have finally understood
new and override.
a.cs
class zzz
get ;
get
}
set
Compiler Error
a.cs(20,1): error CS0546: ‘yyy.i.set’: cannot override because ‘xxx.i’ does not have an
overridable set accessor
In class xxx, the abstract property has only a get accessor. In the derived class we are
implementing both the get and the set. The original never ever had a set. This is unacceptable to
the compiler. Thus we have no choice but to implement only the accessors that are present in the
original. A get accessor can be viewed as a method which returns a value but accepts no
parameters.
a.cs
class yyy
public void i {
Compiler Error
a.cs(3,13): error CS0547: ‘i’ : property or indexer cannot have void type
It makes no sense for an accessor to have a void type as a variable cannot be of type void. Void
literally means ‘I do not know the type’ or no type at all.
a.cs
class yyy
{
public int i {
set
return 10;
Compiler Error
a.cs(6,2): error CS0127: Since ‘yyy.i.set’ returns void, a return keyword must not be followed by
an object expression
A set accessor can be viewed as function which returns void but accepts one parameter which
stands for the value of the property. Thus a set cannot return a value. If we remove the 10, we
will not get an error.
a.cs
class zzz
public int i {
set
value = 20;
}
}
The reserved variable value in the set can be changed at will. Though, understanding why anyone
would want to do such dumb stuff is beyond us.
a.cs
class zzz
public int i {
set
int value;
Compiler Error
a.cs(9,6): error CS0136: A local variable named ‘value’ cannot be declared in this scope because
it would give a different meaning to ‘value’, which is already used in a ‘parent or current’ scope
to denote something else
We cannot however create a variable value as it will clash with the variable value which is
already present by default in the set.
a.cs
class zzz
{
public static void Main()
a.i = 10;
((yyy)b).i = 20;
b.i = 10;
class yyy
public int i {
set {
public int i {
get {
return 10;
}}
Compiler Error
a.cs(9,1): error CS0200: Property or indexer ‘xxx.i’ cannot be assigned to — it is read only
In the class yyy, the property i has only the set accessor. In the class xxx which derives from yyy,
we have implemented only the get accessor. The property i in class xxx hides the i of yyy. They
do not add up. What we are trying to say is that both these properties are independent of each
other. What we had thought C# would have done is, taken the set from one class and added it to
the second. However, that does not make sense. It treats them independently. If we want to use
the property of the class yyy, then we need to explicitly cast it as we have done for b. Thus the
property i of class yyy gets hidden but can be accessed.
A property is not necessarily slower than a variable. A variable access normally initializes some
memory, whereas a property executes a method. This is not necessarily slower as at times, C#
will rewrite your property methods to memory accesses. This is called inlining of code. Except
for minor differences, all that we mentioned about virtual, abstract and new apply also to a
property. The difference is, if the original property has a get and a set, the derived class will only
implement a set or a get.
Indexers
a.cs
a[1] = 10;
Compiler Error
a.cs(6,1): error CS0021: Cannot apply indexing with [] to an expression of type ‘yyy’
We have created an object a that looks like yyy. The object a, in no sense of the word is an array.
We are assuming that a is an array and we’ve used the array syntax a[], hence it gives us an error.
a.cs
a[1] = 10;
set {
Output
in get 10 1
We’ve added a few lines to have the array notation work with an object that looks like yyy. To
implement indexers, we need to create a special property called this. This is a reserved word. As
of now, we have a parameter i (an int) in the square brackets. When we did properties earlier,we
learnt that a set gets called whenever we want to initialize or set a variable. Within the set
accessor we have a special variable called value which stores the value passed to the set, in this
case 10. The variable i will hold the value 1 as the array parameter is 1.
a.cs
System.Console.WriteLine(a[1]);
set
get
{
System.Console.WriteLine(“in set “ + i);
return 23;
Output
in set 1
23
The rules binding properties are applicabe to indexers too. When you want to read the value of
a[1], the get gets called. The major difference between properties and indexers is that when you
implement the code for indexers you have to understand that the get and set get called with a
variable which is the array parameter value. The code will have to understand array simulation.
a.cs
a[“hi”] = 30;
System.Console.WriteLine(a[“hi”]);
public int z;
public int this[string i]
set
z = value;
get
return z;
Output
In get 30 hi
In set hi
30
The this property has a return value, in this case, an int. Also the [] brackets can contain data
types other than an int. In this case a string. The string i has a value hi as that is what we passed
in the array brackets. You can have two this’s in your class. You have to decide what data type to
use in the array brackets. An indexer is very useful when you have a database object and you
want to access the data in the fields using a notation [“fieldname”]
a.cs
class zzz
a[1] = 10;
a[“one”] = 10;
a[“hi”,2] = 30;
class yyy
set
set
{
System.Console.WriteLine(“one string “+ i + “ “ + value);
set
Output
one int 1 10
The signature of an indexer is the number and types of formal parameters. The return value and
the names of the parameters do not contribute to the indexers signature. Thus we have
overloaded the indexers to take an int, string or a string int combination. Each time a different
function gets called. The point to understand is that all the indexers have to return the same data
type, in our case int. The same rules that apply to function overloading apply here also. Functions
cannot differ only by return values. We are sure that for indexers in the next version, C#
should/must make an exception.
A property is identified by its name, an indexer by its signature. There is no concept of property
overloading in C#.
a.cs
class zzz
{
public static void Main()
class yyy
set
Compiler Error
a.cs(9,19): error CS0106: The modifier ‘static’ is not valid for this item
A property can be both an instance member which is the default or static. An indexer
unfortunately can only be an instance member and not static. God alone knows why this
discrimination against indexers. Once again no rational reason for the above error. Obviously
you cannot create a variable with the same name as that of the parameter passed in the indexer.
a.cs
class zzz
System.Console.WriteLine(a[2]);
class yyy
get
return 20;
set
{
get
int p = base[i];
return 200;
set
base[i] = value;
Output
xxx set 20 2
yyy set 20 2
yyy get 2
xxx get 2 20
200
The above example deals with calling the indexers of the base class. At times when we are
overriding code in the derived class, we would like to call the original indexer in the base class
first. The first rule that we have to adhere to is that the indexer in the base class must be declared
virtual. In the derived class, we are now declaring it with the modifier override. Same rules as
above. In the set accessor, we have to call the original as base[i], where i is the index to the
indexer. Also we need to pass it the value to initialize itself. This is stored in the variable value.
This a[2] in Main gets replaced by base[2] in the set. In get the reverse takes place. Here we need
to place base[i] on the right of the equalto sign, the original get will return a value, in this case
20, which we are storing in a variable p. What we do with p as well as the value from the get is
our business.
a.cs
class yyy
get
return 10;
set
return 20
Compiler Error
a.cs(5,1): error CS0111: Class ‘yyy’ already defines a member called ‘get_Item’ with the same
parameter types
a.cs(9,1): error CS0111: Class ‘yyy’ already defines a member called ‘set_Item’ with the same
parameter types
Like a property, an indexer also gets a name change. If people can get their bodies pierced then
why cannot a indexer get converted to a series of functions starting with get? For a get, the
parameters are the same as we pass to an indexer. It has a return value and the type of the
indexer. Also the set has one more added parameter and that is the free variable value.
11
Interfaces and Structures
Constructors Revisited
a.cs
System.Console.WriteLine("in main");
bb a = new bb();
bb b = new bb(10);
public class aa
public aa()
}
public aa(int i)
public class bb : aa
public bb()
public bb(int i)
Output
in main
in const aa
in const bb
in const aa
in const bb10
Class aa is the base class. It consists of two constructors. One that takes no parameters and the
other that takes an int as a parameter. Class bb is derived from class aa, i.e. aa is the base class,
bb the derived class. When we create an object like bb, the compiler does not execute the code
for the constructor but instead asks the constructor which constructor of the base class to execute
first. As we haven't stated this, by default, the constructor with no parameters get executed.
Remember it is the base class constructor which gets executed first and the derived class
constructor specifies which base class constructor to call first. In the second case, even though
we are calling the constructor with a parameter, the constructor with no parameters in the base
class gets called and not the one with one int as a parameter.
a.cs
System.Console.WriteLine("in main");
bb a = new bb();
bb b = new bb(10);
public class aa
public aa()
public aa(int i)
public class bb : aa
Output
in main
in const aa
in const bb
in const aa10
in const bb10
If we do not specify which constructor of the base class to call, C# by default calls the
constructor with no parameters. Which means that C# rewrites our code . When we write bb(), it
gets rewritten as bb() : base(). Base is a reserved word. It means call the constructor of the base
class with no parameters. For the second constructor, bb(int i), the line gets rewritten to bb(int i) :
base(). We now want to call the constructor with one int and hence we write bb(int i) : base(i).
That is why the constructor with one int gets called. We have the option to decide which
constructor of the base class we would like to call.
a.cs
System.Console.WriteLine("in main");
bb a = new bb();
public class aa
public aa()
public aa(int i)
public class bb : aa
Output
in main
in const aa20
in const bb20
in const bb
A constructor gets called at the time of creation of the object. At the line, new bb(), the compiler
asks the constructor of bb as to which constructor of the base class aa to call. Here he was told
that the answer lies with this(20). this, like base, is a reserved word. It means call a constructor of
the same class and not the base class. Therefore the compiler now asks the one constructor of the
derived class bb which constructor of the base class to call. bb(int i) : base(i) tells the compiler to
execute the one int constructor of aa. This is the first constructor that gets called. Then the one
int constructor of bb gets called and finally the one who started it all, the no parameter
constructor of bb. Thus, two derived class constructors get called instead of one.
a.cs
System.Console.WriteLine("in main");
aa a = new aa();
}
}
public class aa
private aa()
Compiler Error
When you create a constructor which is private, you cannot create an object that looks like aa.
Thus aa should only contain static members.
a.cs
public class aa
private aa()
}
public class bb : aa
Compiler Error
Nor can any class derive from aa. Thus no one can instantiate an object that looks like aa or
derive from it as the constructor has been made private.
a.cs
System.Console.WriteLine(aa.i);
public class aa
private aa()
Output
20
You can however use all the static variables in aa
a.cs
class yyy
public yyy()
public int i;
Compiler Error
a.cs(16,15): error CS0027: Keyword this is not available in the current context
Base is called a constructor initializer. When base gets called, the instance or the object has not
yet been created. Ergo, this is not available here as this refers to the current object. In the
constructor, however, this can be freely used.
The values of variables in a class are initialized to their default values as per their data types
before the constructor gets called. Thus, in the constructor they have their default values as
shown below.
a.cs
class yyy
public int i;
public bool j;
public yyy()
Output
0 False
Here as before, the first line of code in the constructor gets executed.
a.cs
class yyy
public yyy(int j)
System.Console.WriteLine(i);
i = j;
System.Console.WriteLine(base.i);
}
Output
10
100
Calling the base class constructor is like inserting all the code of the one int constructor i.e.
yyy(int j), in the constructor of class xxx. We are also allowed to access members of the base
class after the constructor gets called. Also, first the variable i gets initialized to 10 or the default
value of int. Then we change it to 100 and in the constructor of xxx, we will see a value of 100.
a.cs
class yyy
public yyy()
abc();
{
}
public xxx()
System.Console.WriteLine(x);
x = 100;
System.Console.WriteLine(x);
System.Console.WriteLine(x);
Output
10
10
100
We have already confessed a million times in the past that we have copied ideas from anyone and
everyone, specially from the documentation. In this specific case, we wanted to demonstrate that
first the variables are initialized. Thus in class xxx, the int x is initialized to 10. Then the base
class constructor of yyy gets called. The value of x in class yyy should be 10. But what guarantee
can we give you as we are not able to print the value of x in an object of a class derived from the
base class. Very simple. We call a virtual function abc from class yyy and override it in class xxx.
The abc of class xxx prints the value of x as they belong to the same class and the output is 10.
Viola and thank you Mr. Documentation for the above thought and many more such ideas. Once
all code in the yyy constructor is executed, the first line in xxx constructor will get executed
which will print the value of x as 10. x is then initialized to 100, hence we see 100 as the new
value of x, displayed on the screen.
a.cs
static zzz()
System.Console.WriteLine("zzz");
System.Console.WriteLine("main");
new aa();
public class aa
public aa()
System.Console.WriteLine("aa");
static aa()
{
System.Console.WriteLine("static aa");
Output
zzz
main
static aa
aa
and if we comment new aa() then the resulting output reads as follows.
Output
zzz
main
a.cs
static zzz()
System.Console.WriteLine("zzz");
{
System.Console.WriteLine("main");
aa.a();
public class aa
public aa()
System.Console.WriteLine("aa");
static aa()
System.Console.WriteLine("static aa");
Output
zzz
main
static aa
If you try to access any static member of a class or whenever you instantiate an object, the static
constructor gets called. A constructor is not inherited by the derived class.
A class is loaded in memory before any instance of the class is created or its static members
accessed. A class can only be loaded once and that too before its derived class is loaded. The
static constructor is called at the time of loading the class. Like other constructors, a static
constructor cannot be explicitly called.
a.cs
xxx.pqr();
yyy.abc();
class yyy {
static yyy()
System.Console.WriteLine("static yyy");
System.Console.WriteLine("abc yyy");
class xxx {
static xxx()
{
System.Console.WriteLine("static xxx");
System.Console.WriteLine("pqr xxx");
Output
static xxx
pqr xxx
static yyy
abc yyy
Do not believe the above results as if you run them on your machine, your mileage may wary.
This is because C# does mandate the order of loading of classes and thus the order of execution
of the static constructors. On your machine if the yyy constructor gets executed first, do not
panic. Blame it on your destiny.
a.cs
yyy.abc();
xxx.pqr();
}
}
class xxx
static xxx()
System.Console.WriteLine("static xxx");
System.Console.WriteLine("pqr xxx");
static yyy()
System.Console.WriteLine("static yyy");
System.Console.WriteLine("abc yyy");
}
Output
static yyy
abc yyy
static xxx
pqr xxx
We have made only one small change in the above program. We have derived the class yyy from
xxx. Since the functions in each class are marked static, the program behaves in the same manner
as before.The above order of calls remains the same. If an object of the type is created, then the
output will change. The reason being that before the object of type yyy is created, xxx must be
loaded. Hence the constructors will be called first.
a.cs
static zzz()
x = 500;
yyy.y = 600;
}
}
class yyy
static yyy()
y = 10;
zzz.x = 200;
Output
static yyy 0 3
static zzz 12 10
Difficult code to understand and follow. C# first tries to load class zzz in memory as it contains
the function Main. Unfortunately it realizes that it has to first initialize the variable x before
calling the static constructor of zzz. It first initializes x to 0. Now note that this initialization of x
to zero is extremely significant for our understanding. To get the new value of x, C# now needs
the value of the variable y from the class yyy. Before it can call the static constructor of yyy it
must initialize the variable y. It makes sure that y's value is first set to zero. It then computes the
value of zzz.x which is zero as stated above. We are yet left hanging in class zzz at the line x = .
As zzz.x is zero, the value of y is 0 + 3 i.e. 3. This completes the initialization of all the variables
in the class. All this happens first. Thus the static constructor of class yyy shows the value of the
variable x as 0 and that of variable y as 3.
But hold on, the fun is yet to begin. In the static constructor, we now initialize y to 10 and the x
of zzz to 200. The next WriteLine confirms that our initializations actually were carried out.
Then we go back to class zzz. Here we come back to the initialization of the static variable x. As
yyy.y is now 10 since we changed it in the static constructor of yyy, the value of x is 10 + 2 i.e.
12. This overrides the value of x which we changed to 200 in the static constructor yyy. Now C#
calls the static constructor of zzz as it has finished all the variable initializations. Thus the first
WriteLine displays 12 and 10. We are now changing both x and y and they display the same
values in the constructor and in Main.
a.cs
static zzz()
x = 500;
yyy.y = 600;
class yyy
static yyy()
y = 10;
zzz.x = 200;
System.Console.WriteLine("static yyy " + zzz.x + " " + yyy.y);
Output
static zzz 2 0
main 200 10
The above program adds a small twist. It bowls what in cricket parlance is called a googly. We
simply bring Main from the class zzz to the class yyy. Now C# as usual first starts at the class
containing Main which now happens to be yyy and not zzz. Here it has to first initialize all the
variables in class yyy. We have only one. It starts by setting y to zero and runs to the class zzz to
fetch the value of x. x now become 0 + 2 i.e. 2. Then in the static constructor, we are displaying
the relevant values of x and y. In the static constructor of class zzz, we are changing x and y to
500 and 600 respectively and displaying the values. When we move back to class yyy, however,
y gets a new value of 503 as x is 500. y loses its value of 600 that was initialized in zzz, hence
you see 500 and 503. The rest remains the same as explained in the earlier example.
Interfaces
An interface is simply a collection of function prototypes. Like we derive a class from another,
so also we could derive from an interface.
a.cs
class zzz
{
interface ddd
void a1();
void a2();
Compiler Error
a.cs(12,7): error CS0535: 'yyy' does not implement interface member 'ddd.a1()'
a.cs(12,7): error CS0535: 'yyy' does not implement interface member 'ddd.a2()'
We have just created an interface called ddd by using a new keyword interface in place of a class.
Our interface ddd has two function prototypes, a1 and a2. We can derive from our interface ddd
like we derived from a class. The difference is that an interface has no code, only function
prototypes. Whenever we derive from an interface, we have to implement the code or body of the
function. A class gives you lots of free code, an interface does not. The error is generated as we
have not given the code for a1 and a2 in yyy
a.cs
class zzz
a.a1();
d.a2();
interface ddd
void a1();
void a2();
System.Console.WriteLine("yyy a1");
System.Console.WriteLine("yyy a2");
Output
yyy a1
yyy a2
We get no errors because we have now implemented the code of a1 and a2. Looks wise we do no
know whether ddd is a class or an interface as the syntax at the time of derivation is the same. d
is an object that looks like an interface which is syntactically correct. d can be equated to a yyy
as a yyy is a yyy + a ddd. We can, by only using d, call members of a ddd.
a.cs
class zzz
aaa a ;
a = new aaa();
interface aaa
Compiler Error
a.cs(6,5): error CS0144: Cannot create an instance of the abstract class or interface 'aaa'
Even though an interface aaa is empty, we cannot write the keyword new in front of it. An
interface contains no code and thus cannot be instantiated. However we are allowed to declare
objects that look like an interface. Therefore, in this case, the line aaa a, does not flag an error.
a.cs
class zzz
{
public static void Main()
interface aaa
void a1()
Compiler Error
Reiterating, an interface can only contain function prototypes, no code at all. The functions
cannot have a definition.
a.cs
class zzz
class xxx
}
class vvv
Compiler Error
C# does not support multiple inheritance. We can derive from a single class only at one point in
time.
a.cs
class zzz
d.a1(); d.a2();
a.a1();
a.a2();
interface ddd
{
void a1();
void a2();
System.Console.WriteLine("a1");
System.Console.WriteLine("a2");
Compiler Error
a.cs(19,13): error CS0106: The modifier 'public' is not valid for this item
You are not allowed to use the modifier public for a function which has qualified its name with
that of the interface.
a.cs
class zzz
}
}
interface aaa
Compiler Error
a.cs(9,13): error CS0106: The modifier 'public' is not valid for this item
Interface members are public by default. The access modifiers are not allowed here. All the other
access modifier rules remain the same as that from classes. The rules in classes stated that the
base class must be at least as accessible as the derived class. Replace the word class with
interface and you will not be sorry.
a.cs
class zzz
d.a1(); d.a2();
a.a1();
a.a2();
interface ddd
{
void a1();
void a2();
void ddd.a1()
System.Console.WriteLine("a1");
System.Console.WriteLine("a2");
Compiler Error
a.cs(8,1): error CS0117: 'yyy' does not contain a definition for 'a1'
The reason we get an error is because we created the function a1 in yyy as ddd.a1 and not a1. By
doing this, we were telling C# that only objects that look like ddd are allowed access to a1. Even
an object that looks like yyy is not allowed to access a1. Comment out line number 8 i.e. a.a1
and all works fine as follows
Output
a1
a2
a2
a.cs
class zzz
a.a1(); a.a2();
d.a1();
e.a2();
interface ddd
void a1();
interface eee
void a2();
System.Console.WriteLine("a1");
System.Console.WriteLine("a2");
Output
a1
a2
a1
a2
Here we are doing something that just cannot be done with classes. We are deriving from two
interfaces ddd and eee at the same time. Each has one function prototype a1 and a2 respectively.
Using a which looks like yyy we can call both a1 and a2 but with d that looks like ddd we can
only call a1. Similarly, with e only a2 can be called.
a.cs
class zzz
d.a1();
e.a1();
interface ddd
void a1();
interface eee
void a1();
System.Console.WriteLine("a1");
Output
a1
a1
a1
The two interfaces share the same function name a1. We do not get an error but yet things do not
seem right. Both d and e call the same a1 and there is only one implementation of the function
a1. We would like to have two a1's but we cannot have the same function defined twice in a
class.
a.cs
class zzz
d.a1();
e.a1();
interface ddd
void a1();
interface eee
void a1();
void ddd.a1()
System.Console.WriteLine("ddd a1");
void eee.a1()
System.Console.WriteLine("eee a1");
Output
ddd a1
eee a1
We did what we had explained earlier. We prefaced the name of the function with the name of
the interface. Then we removed the modifier public and the object a which looked like yyy. Now
each interface has its own copy of a1 to be called. ddd.a1 is called the explicit interface member
name.
a.cs
class zzz
a.a1();
}
}
interface ddd
void a1();
interface eee
void a1();
void ddd.a1()
System.Console.WriteLine("ddd a1");
void eee.a1()
System.Console.WriteLine("eee a1");
Compiler Error
a.cs(6,1): error CS0117: 'yyy' does not contain a definition for 'a1'
The reason we removed a was that once we have an explicit interface member, we cannot access
it through the class, it is done only through the interface. This make a lot of sense as there are
two functions of the same name, and C# does not know which one it should call. By prefacing
the functions with the names of the interface, we are making them part of the interface and not
the class. In a sense they are private to the class. As there is no function by the name of a1 in
class yyy, we see the above error.
a.cs
class zzz
interface ddd
void a1();
interface eee
void a1();
void ddd.a1()
void eee.a1()
{
Compiler Error
a.cs(21,6): error CS0540: 'yyy.eee.a1()': containing class does not implement interface 'eee'
We get an error as class yyy is derived only from interface ddd. Thus we cannot use eee.a1() as
interface eee is not a base interface for class yyy.
a.cs
class zzz
interface ddd
void a1();
void ddd.a1()
}
class xxx : yyy
void ddd.a1()
Compiler Error
a.cs(19,6): error CS0540: 'xxx.ddd.a1()': containing class does not implement interface 'ddd'
The key concept earlier was that we could only use the name of an interface explicitly if it was
categorically stated as a base class. Anything indirect would not do. Here class yyy is derived
from interface ddd and thus we can use the form ddd.a1. However even though class xxx is
derived from class yyy and thus also from interface ddd, we are not allowed to write ddd.a1 as
interface ddd is not explicitly stated in the derivation list of class xxx.
An interface defines a contract and can only contain four entities viz methods, properties, events
and indexers. An interface thus cannot contain constants, fields, operators, constructors,
destructors, static constructors, or types. Also an interface cannot contain static members of any
kind. The modifiers abstract, public, protected, internal, private, virtual, override are disallowed
as they make no sense in this context.
a.cs
class zzz
int a2
get; set ;
event d1 ddd;
string this[int i]
get; set;
}}
The above example demonstrates the four entities an interface can contain. Anything else will
flag an error.
a.cs
class zzz
aaa a = c;
bbb b = c;
c.a1();c.a2();
a.a1();
b.a1();b.a2();
}
interface aaa
void a1();
void a2();
System.Console.WriteLine("a1");
System.Console.WriteLine("a2");
Output
a1
a2
a1
a1
a2
An interface can also, like a class, inherit from one or more interfaces. In this case bbb as an
interface, can inherit from aaa. The class ccc inherits from interface bbb and and thus interface
aaa has to implement functions a1 and a2. The object c not only looks like a ccc but also looks
like an aaa and bbb. Thus equating them does not give an error. The reverse, however, is not true.
It will obviously flag an error. However a can only access functions from the interface it belongs
to, in this case a1 and b can access a1 and a2. b cannot access members from class ccc even
though a, b, and c have the same values. Whenever an interface derives from another it is called
an explicit base interface. Like classes, circular definitions are not permitted. In fact nowhere in
the C# programming language are we permitted to have circular definitions.
An interface also creates a new type and as in classes, methods must have their own unique
signatures. Properties and methods cannot have similar names.
a.cs
class zzz
interface aaa
void a1();
{
void a1();
Compiler Warning
a.cs(13,6): warning CS0108: The keyword new is required on 'bbb.a1()' because it hides
inherited member 'aaa.a1()'
Like classes if interfaces derive from each other, there is a possibility that they may contain the
same function signatures. Thus we get a warning which can be removed by adding the keyword
new as follows.
The point to be stressed here is that the keyword new really does not do much, other than remove
the warning. This is because the implementation of the interface is done in the class. There, we
will have only one implementation of function a1 and not two, one for aaa and the other for bbb.
At one level, from the point of view of the class which derives from interface bbb, it will see
only one function in it, not two. All that we are doing is hiding the base interface member.
a.cs
class zzz
void abc(ccc c)
c.aa(1);
((bbb)c).aa(1);
((aaa)c).aa(1);
c.aa = 2;
((aaa)c).aa = 3;
((bbb)c).aa = 3;
interface aaa
int aa
get; set;
interface bbb
Compiler Error
a.cs(10,10): error CS0118: 'aaa.aa' denotes a 'property' where a 'method' was expected
a.cs(11,1): error CS0229: Ambiguity between 'aaa.aa' and 'bbb.aa(int)'
Interface aaa has only one member, a property called aa, whereas interface bbb has one function
called aa. The interface ccc does not give us an error in spite of the fact that we have a property
and a function with the same name. In the function abc, we are passing c, an object that looks
like ccc. The line c.aa(1) gives us an error as we have a property and a function called aa. C# gets
confused whether it is the property or the function we are referring to. In our humble opinion, we
could only be referring to the function as per the syntax, but you don't argue with a compiler.
In the second case c.aa = 2 also flags an error due to the name confusion. In this case also, we
could only be referring to a property. The only way out is to cast. The second cast in each case
gives an error as the syntax for calling a function and property is different. Normally, to cast, we
need to give two sets of brackets.
A cast incurs no run time costs i.e., it does not slow down the program. All that a cast does in the
above case is lowers the pointer from a ccc to aaa or bbb at compile time. In an earlier example,
we spoke of functions from two interfaces having similar names. The same rules stated there
apply here also.
a.cs
class zzz
void abc(ccc c)
c.aa(1);
c.aa((byte)1);
((aaa)c).aa(1);
((bbb)c).aa(1);
}
}
interface aaa
interface bbb
Compiler Error
a.cs(8,1): error CS0121: The call is ambiguous between the following methods or properties:
'bbb.aa(short)' and 'aaa.aa(byte)'
a.cs(9,1): error CS0121: The call is ambiguous between the following methods or properties:
'bbb.aa(short)' and 'aaa.aa(byte)'
We have a similar problem again. c.aa(1) does not know which function aa to call. C# could
convert the 1 an int, either to a short or a byte. Thus the ambiguity. Even if we cast the 1 to a
byte, for some reason, C# yet gives us an error. The only way out is like what we did earlier,
explicitly cast your way out of trouble. When we cast, we are restricting ourselves to only one
method and thus no ambiguity.
a.cs
class zzz
interface aaa
void aa();
void cc();
Compiler Error
a.cs(22,7): error CS0535: 'eee' does not implement interface member 'bbb.aa()'
a.cs(22,7): error CS0535: 'eee' does not implement interface member 'ccc.cc()'
a.cs(22,7): error CS0535: 'eee' does not implement interface member 'aaa.aa()'
The interface aaa has one function aa. The interface bbb is derived from aaa and also has one
function called aa. The keyword new informs the C# compiler that, it has hidden or has nothing
to do with the function aa in interface aaa. Remember in interfaces, we cannot write any code.
The interface ccc also derives from aaa but does not have a function called aa. Then we are
creating another interface ddd which derives from both bbb and ccc. The class eee is then derived
from interface ddd. We get three errors as we have to implement three functions in class eee.
The interface ccc brings in two functions. One cc and the other aa from interface aa. The
interface bbb has only one function, aa which is different from the aa which is present in
interface aaa, thanks to the keyword new which is optional.
a.cs
class zzz
a.aa();
b.aa();
c.aa();
d.aa();
//e.aa();
((aaa)d).aa();
((bbb)d).aa();
((ccc)d).aa();
((ddd)d).aa();
interface aaa
void aa();
void cc();
void aaa.aa()
{
12
Operator Overloading
Let’s explain what operator overloading is all about with an example of a class that represents a
date. Would it not be great if we could subtract two date objects and be returned an int
representing the number of days elapsing between the two dates. We would like to use the good
old subtraction operator – like we do when subtracting numbers. Also we would like the >
operator to compare two date objects and tell us which one is larger. The + operator could add a
number to a date resulting in a new date object.
Thus, operator overloading lets us redefine the existing operators so that they work with
classes/objects we create like yyy. We have not yet instructed C# on how to use the trusty old +
operator with two yyy objects. Though C# knows how to use the + to add two numbers, it does
not know how to add two yyy’s.
a.cs
yyy c;
c=a+b;
}
public int i;
i = j;
Compiler Error
a.cs(8,5): error CS0019: Operator ‘+’ cannot be applied to operands of type ‘yyy’ and ‘yyy’
We have created a simple class yyy which has one instance variable i which will distinguish
different instances of yyy from each other. The constructor with an int as a parameter initializes i.
We have tried to add two objects that look like yyy which does not go down well with C# and it
objects to it.
a.cs
yyy c;
c=a+b;
}
public int i;
i = j;
Compiler Error
a.cs(18,12): error CS0558: User-defined operators ‘yyy.operator +(yyy, yyy)’ must be declared
static and public
Error messages can be at times helpful. Our operator + is public but not static. C# demands that
all operator overloads be static.
a.cs
c=a+b;
System.Console.WriteLine(c.i);
public int i;
i = j;
return z;
Output
operator + 10 5
15
The word operator as the name of a function, is legal and the only way to overload operators. We
follow this word with the operator we want to overload and then the parameters we will call the
operator with. + is a binary operator and will need two yyy’s, one on its left and the other on its
right. Then at beginning, we give the return value of the operator. In our case we want a + to add
two yyy’s and return a third yyy whose i will be the sum of the individual i’s. Thus a+b will call
the operator + with x being equal to a and y to b. Thus x.i will have a value 10 and y.i, 5. We are
creating a new object z and in the constructor passing 15 i.e. 10 + 5. Thus the i of z will be 15
which is being returned. a + b will now be replaced by the object whose i has a value 15 and c
will be equal to this object. Thus c.i will be equal to 15.
a.cs
yyy c;
c=a+b;
System.Console.WriteLine(c.i);
public int i;
i = j;
return z;
Compiler Error
The error message is telling us that we cannot overload the assignment operator =. Every class
gets a free assignment operator which does a bitwise copy of the variables of the object from the
left to the right.
a.cs
yyy d;
d=a+b+c;
System.Console.WriteLine(d.i);
public int i;
i = j;
return z;
Output
Operator + 10 5
Operator + 15 2
17
The only change is d = a + b + c. C# gets easily confused with complex statements so it does not
read all of it. It sees two operators on the same line. In this case, the same plus. An internal rule
tells it to read the plus left to right i.e. it will only see a + b. It will call the operator + with x.i as
10 and y.i as 5 because a’s i is 10 and b’s i is 5. This will create a temporary object like yyy
whose i is 15, lets call it zz. The object z is very different from zz. C# then evaluates zz + c. Thus
x.i will display 15 and y.i will have the value of c.i i.e. 2. To support multiple invocations of the
operator on a single line, the code does not change.
a.cs
int d = a + b ;
System.Console.WriteLine(d);
public int i;
i = j;
Output
operator + 10 5
15
C# does not and will never understand what addition of two yyy’s is all about. It is in your hands
to decide what the code accomplishes. You decide whether the overloaded + returns a yyy or an
int object. The class yyy is your creation not C#’s. Hence you decide what addition means in the
context of a yyy class. In this case, we are returning an int unlike earlier where we returned a
yyy.
a.cs
int d = a + b ;
System.Console.WriteLine(d);
public int i;
public yyy( int j)
i = j;
return z;
Compiler Error
a.cs(23,19): error CS0111: Class ‘yyy’ already defines a member called ‘ op_Addition ‘ with the
same parameter types
You cannot have two operator + overloads which only differ in return types. Also the error
messages change the name of the operator from + to op_Addition. When we overloaded
functions, the return type was not considered part of the function signature. The same applies for
operators.
a.cs
yyy d = a + b + 20;
System.Console.WriteLine(d.i);
public int i;
i = j;
return z;
}
Compiler Error
a.cs(7,9): error CS0019: Operator ‘+’ cannot be applied to operands of type ‘yyy’ and ‘int’
C# is now telling you that you can add two yyy’s but cannot do the same, i.e. add a yyy and an
int as we have not told C# how to do so.
a.cs
yyy d = a + b + 20;
System.Console.WriteLine(d.i);
public int i;
i = j;
{
System.Console.WriteLine(“operator + “ + x.i + “ “ + y.i);
return z;
return z;
Output
Operator + 10 5
Operator + 15 20
35
Life is fun in the fast lane. As we could have a large number of functions with the same name but
differing number of parameters, ditto for operators. a + b as usual calls the first operator +. This
as usual creates a temp object, say zz and now C# reads the line as zz + 20. This matches the
second operator + which now gets called. You can have over a million plus operators with
differing parameters if you desire.
a.cs
{
yyy a = new yyy(10);
if ( a > b )
System.Console.WriteLine(“true”);
else
System.Console.WriteLine(“false”);
public int i;
i = j;
Compiler Error
a.cs(20,20): error CS0216: The operator ‘yyy.operator >(yyy, yyy)’ requires a matching operator
‘<‘ to also be defined
C# is a romantic at heart and loves pairs. We tried to overload the > operator and C# tells us that
we have to also overload the < operator. It makes sense as a user would want to know whether a
yyy is greater than or less than another yyy.
a.cs
if ( a > b )
System.Console.WriteLine(“true”);
else
System.Console.WriteLine(“false”);
public int i;
i = j;
Output
operator > 10 5
true
The operator < returns a bool as we would like to use it as part of an if or a while. In this case we
are using it as part of an if and nothing stops us from using the < overloaded for ints and yyy’s to
return a bool. What code you write in an operator is entirely your decision. The < operator looks
like the + and can take different parameters. To overload the !=, you also have to overload the
==.
a.cs
System.Console.WriteLine(a);
System.Console.WriteLine(a.ToString());
public int i;
i = j;
Output
yyy
yyy
In the first WriteLine function to be called, we are passing the object a whereas the first
parameter to WriteLine should be a string. Also we do not get an error and we see yyy displayed.
A longtime back we told you that all classes finally derive from object. The class object has a
function ToString. Thus calling the ToString function off a produces the same output as the above
line. We have not created the ToString function. So either we got a free ToString implementation
from C# like we get a free Constructor or the ToString function of object in some way
determines the name of our class and returns it as a string.
a.cs
{
yyy a = new yyy(10);
System.Console.WriteLine(a);
System.Console.WriteLine(a.ToString());
public int i;
i = j;
System.Console.WriteLine(“ToString”);
return “mukhi”;
Compiler Warning
Output
yyy
ToString
mukhi
WriteLine displays yyy and a.ToString displays mukhi. Which means that they call different
ToString functions. The WriteLine(a) calls the ToString of object whereas the second WriteLine
calls it of yyy. If we want to override a function in the base class, we have to specifically do so
by using the modifier override. If we do not, the default is to call the base class ToString. All this
has been explained earlier, in any case.
a.cs
System.Console.WriteLine(a);
System.Console.WriteLine(a.ToString());
public int i;
i = j;
}
public override string ToString()
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
ToString
mukhi
ToString
mukhi
Now both the System.Console.WriteLine calls the ToString function of yyy. We would like to
convert a yyy into a string or an int for example. These type conversions are a major part of
operator overloading.
a.cs
System.Console.WriteLine(a);
}
public class yyy
public int i;
i = j;
System.Console.WriteLine(“operator string”);
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
operator string
string 10
In spite of having a function ToString, it does not get called unlike earlier. After the keyword
operator we have the name of a data type i.e. string. This function is called whenever we want to
convert our object into a string. The parameter y stands for the object to be converted. In this
function we can write whatever code we want to but we must return a string. In our case we
return the text string concatenated with the current value of i.
Once again, the WriteLine function requires a string class. We are offering a yyy class. C#
checks whether there is an operator string which is available to convert a yyy into a string. As
there is one, it gets called. The word implicit means that we are indirectly implying that it should
be called. Lets explain this with another example.
a.cs
string s;
s = a;
System.Console.WriteLine(s);
public int i;
i = j;
System.Console.WriteLine(“operator string”);
System.Console.WriteLine(“ToString”);
return “mukhi”;
Compiler Error
We have changed the word implicit which means imply. It also means giving a hint with the
word explicit which means specify. Had we not changed implicit with explicit, we would have
got no error and C# would have called the operator to convert a into a string and initialize s to it.
a.cs
string s;
s = (string)a;
System.Console.WriteLine(s);
}
public int i;
i = j;
System.Console.WriteLine(“operator string”);
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
operator string
string 10
The () is called a cast and it takes any data type within brackets. We are explicitly asking for a
conversion to a string and unlike earlier we are not being implicit but explicit.
a.cs
string s;
s = (string)a;
System.Console.WriteLine(s);
System.Console.WriteLine(a);
public int i;
i = j;
System.Console.WriteLine(“operator string”);
return “string “ + y.i;
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
operator string
string 10
ToString
mukhi
The explicit will get called only when we cast and as we do not have an implicit modifier, the
ToString gets called. We get no error if we do not have an implicit modifier.
a.cs
string s;
s = (string)a;
System.Console.WriteLine(s);
System.Console.WriteLine(a);
public int i;
i = j;
System.Console.WriteLine(“operator string”);
System.Console.WriteLine(“operator string”);
System.Console.WriteLine(“ToString”);
return “mukhi”;
Compiler Error
We cannot have both the implicit and explicit modifier as two separate functions. Thus you have
to decide which one you would want to implement.
a.cs
yyy a ;
a = 10;
public int i;
i = j;
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
One more error. Here we are trying to equate a yyy to an int but unlike earlier, we have not
created an object like yyy by saying new. We would need someone to create the yyy object and
initialize it to 10, an int.
a.cs
yyy a ;
a = 10;
System.Console.WriteLine(a.i);
public int i;
i = j;
return z;
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
10
A constructor has the same name as the name of the class. Thus operator yyy may double up as a
constructor. When we write a = 10, C# calls this constructor and passes the parameter v a value,
10. Operator yyy has now to create an object that looks like yyy and return it. Thus it does not
act like a constructor in the sense that a constructor is responsible for creating the object. In
other words, writing a = 10, creates a new object that looks like yyy and initializes it to 10. It is
different from what we did earlier as previously the operator did not have to create an object that
looks like yyy. In this case it has to.
a.cs
public class zzz
yyy a ;
a = “Hi”;
System.Console.WriteLine(a.i);
public int i;
i = j;
return z;
return z;
System.Console.WriteLine(“ToString”);
return “mukhi”;
Output
100
We can have as many operator yyy functions as we like, provided we follow the rules of function
overloading. Thus we have two of them, one that takes a string, another that takes an int. In this
case as we are writing a = “hi”, the second operator that accepts a string get called. They all have
to return an object that looks like yyy.
a = (short) 10;
Had we written the above line, we will not get any errors. We assumed we will get an error as we
do not have an operator yyy which takes a short as a parameter. C# is highly intelligent. It first
checks whether we have an operator yyy that matches what we wrote. In no case, there is a
match. It will then check whether there is any other way it can prevent an error from being
signaled. C# realizes that there is an operator yyy which accepts an int. Thus it converts a short
to an int and then calls the operator yyy with the int parameter.
13
Collection Objects
Earlier we used an array in a foreach. If the array had three members, the foreach got executed
three times and each time the variable i had a different value. The concept described below is
called a collection class. It is a class that returns a value each time till the values run out, thus
making it easier for us to iterate through the array.
a.cs
foreach (string i in f)
class yyy
}
Compiler Error
a.cs(6,1): error CS1579: foreach statement cannot operate on variables of type ‘yyy’ because
‘yyy’ does not contain a definition for ‘GetEnumerator’, or it is inaccessible
a.cs
foreach (string i in f)
class yyy
Compiler Error
a.cs(6,1): error CS1579: foreach statement cannot operate on variables of type 'yyy' because 'int'
does not contain a definition for 'MoveNext', or it is inaccessible
a.cs(13,12): error CS0161: 'yyy.GetEnumerator()': not all code paths return a value
Foreach obviously tries to execute the function called GetEnumerator. This function should not
return an int but something else as the error suggests.
a.cs
using System.Collections;
foreach (string i in f)
class yyy
{
}
Compiler Error
IEnumerator is an interface which has three functions MoveNext, Reset and Current and xxx has
to implement all of them to remove the compiler errors.
a.cs
using System.Collections;
foreach (string i in f)
System.Console.WriteLine(i);
class yyy
{
public IEnumerator GetEnumerator()
System.Console.WriteLine(“MoveNext”);
return true;
System.Console.WriteLine(“Reset”);
get
System.Console.WriteLine(“Current”);
return “hi”;
}
}
Run the program and you will notice that the output does not stop. It goes on forever.
a.cs
using System.Collections;
foreach (string i in f)
System.Console.WriteLine(i);
class yyy
i++;
System.Console.WriteLine(“MoveNext” + i);
if ( i == 3)
return false;
else
return true;
System.Console.WriteLine(“Reset”);
{
get
System.Console.WriteLine(“Current “ + a[i]);
return a[i];
Output
MoveNext0
Current hi
hi
MoveNext1
Current bye
bye
MoveNext2
Current no
no
MoveNext3
We have created an array a which has 3 members and initialized them respectively to hi, bye and
no by giving the strings in {} immediately after the new. Each time MoveNext gets called the
variable i is increased by 1. If the value of i is 3, we have no more strings to return and thus we
return false, else we return true. The variable i keeps track of how many times the function
MoveNext is being called. As MoveNext returns true, Current gets called which returns a string
from the array using i as the offset. Thus we can iterate through the entire array depending upon
the length.
a.cs
using System.Collections;
foreach (string i in f)
System.Console.WriteLine(i);
class yyy
string t;
t = t1;
}
}
public string [] a;
b[0] = ‘ ‘;
a = t3.Split(b);
i++;
System.Console.WriteLine(“MoveNext “ + i);
if ( i == a.Length)
return false;
else
return true;
System.Console.WriteLine(“Reset”);
}
get
System.Console.WriteLine(“Current “ + a[i]);
return a[i];
Output
MoveNext 0
Current This
This
MoveNext 1
Current is
is
MoveNext 2
Current Great
Great
MoveNext 3
Pretty big program. At the time of creating a yyy object we are passing a string to the constructor.
Thus the yyy constructor gets called first. The constructor stores this string in variable t. The
foreach statement calls GetEnumerator which now creates a xxx object passing it the string
through t. The constructor of xxx now gets called. Every string class has a member function
called Split. Split will break up a string on certain characters which we call delimiters. In this
case, we want our string to be broken up whenever we encounter a space. The Split function
requires an array of chars which it can use as a delimiter. The reason it requires an array is
because we may have more than one char that we would like to break the string on. Like earlier,
the array a now contains the array of strings. The last change is the condition in the if statement.
Earlier we used a constant number, now we use a member, Length, of an array which stores the
length of the array or the number of members. Thus the class yyy can now be used as a collection
class which enumerates the individual words in the string. The function Reset for some reason
never ever gets called.
14
Attributes, The Reflection API And Conditionals
Attributes
a.cs
class zzz
[vijay]
class yyy
{
}
Compiler Error
a.cs(7,2): error CS0246: The type or namespace name 'vijay' could not be found (are you missing
a using directive or an assembly reference?)
Anything in a square bracket is called an attribute. We tried to create an attribute called vijay,
which C#, for some reason, does not seem to recognize.
a.cs
class zzz
[vijay]
class yyy
All that we have done is created a class vijay that has been derived from the class
System.Attribute and the error simply disappears. Thus an attribute is simply a class that derives
from System.Attribute. To understand attributes lets take an example with structures.
a.cs
class zzz
{
a.i = 65536+512+3;
struct yyy {
public int i;
public short j;
public byte k;
Output
66051 0 0
A simple revision once again. We have created a structure a, that looks like yyy and initialized
only one member i. Hence we see the warnings. The other members j and k get a default value of
zero.
a.cs
using System;
class zzz
{
Console.WriteLine(sizeof(byte) + " " + sizeof(short) + " " + sizeof(int) + " " + sizeof(long));
>csc a.cs
Compiler Error
a.cs(4,27): error CS0227: Unsafe code may only appear if compiling with /unsafe
The error here says that you have to use the /unsafe option while compiling any unsafe code.
Output
1248
We shall explain the modifier unsafe in the next chapter. Sizeof tells us how much memory C#
allocates for a data type. A byte is allocated one memory location, short 2, int 4 and a long 8.
a.cs
using System.Runtime.InteropServices;
class zzz
a.i = 65536+512+3;
[StructLayout(LayoutKind.Explicit)]
struct yyy
Output
66051 515 3
Every variable is stored in memory. FieldOffset indicates the starting position of the variable
within the memory location. Offset of 0 will position i, j, and k, all three variables at the same
memory address of a. Explicit requires FieldOffset to be mentioned as we are explicitly laying
the order for the variables held in the strucuture.LayoutKind.Sequential and LayoutKind.Auto
gives different memory locations to each of the variable.
We will explain the reasons a little later in the coming chapter ‘Unsafe Code’. We have seen how
important attributes are so lets delve deeper into them.
a.cs
class zzz
[vijay]
class yyy
[vijayAttribute]
class yyy1
We are allowed a little leeway in the name of the attribute. By convention, the attribute class
should end with the word Attribute and when we use the attribute, the name attribute is optional.
a.cs
class zzz
[vijay("hi")]
class yyy
{
Compiler Error
a.cs(10,2): error CS1501: No overload for method 'vijay' takes '1' arguments
We had used the attribute StructLayout earlier where we passed a parameter. When we do the
same thing with our attribute vijay, we get the above error.
a.cs
class zzz
public vijay(string s)
[vijay("hi")]
class yyy
}
We forgot to add a constructor that accepts a string as a parameter. If we had passed a number to
our attribute vijay, we would have to create a constructor that accepts an int. Thus if we pass 2
parameters to vijay, we need the appropriate constructor.
a.cs
class zzz
[vijay("hi",10,mukhi = 200)]
class yyy
Compiler Error
a.cs(13,16): error CS0103: The name 'mukhi' does not exist in the class or namespace 'vijay'
What we tried to do is, take a word called mukhi and initialize it to 200. C# comes back and tells
us that it does not know what mukhi is.
a.cs
class zzz
[vijay("hi",10,mukhi = 200)]
class yyy
a.cs
class zzz
{
}
get
return "ss";
set
class yyy
{
}
Compiler Error
a.cs
using System.Runtime.InteropServices;
using System;
class zzz
[AttributeUsage(AttributeTargets.Class)]
set { ; }
class yyy
Compiler Error
a.cs(24,2): error CS0592: Attribute 'vijay' is not valid on this declaration type. It is valid on 'class'
declarations only.
AttributeUsage is one more attribute class derived from Attribute. It gives us the option to decide
where the user can use the Attribute. The parameter in this case is class and hence we can use it
only in front of a class and not in front of a method. The default is anywhere.
Reflection or Introspection is when you look within to find out about your true self. In the same
way we need a method by means of which, our program can find out all about a class. We need
to know how many methods, properties etc while our program is executing or running. This
distinction is important and we could always read the documentation if we wanted to know more
about the functionality of a class. But, C# gives us a large number of functions that tell us the
innards of a class. These functions put together have to be used in a certain way. The functions
have to be called in a certain order and the parameters to them have to conform to certain data
types. This concept is called an API or a Application Program Interface. In short, an API is how a
programmer uses functions to get a desired result.
a.cs
using System;
class zzz
Type m;
m = typeof(int);
m = typeof(System.Int32);
m = typeof(yyy);
class yyy
Output
Int32 System.Int32
Int32 System.Int32
yyy yyy
Typeof is a keyword. It needs a class name as a parameter. In the first case, we are specifying a
class called int. typeof returns an object that looks like Type. This class has two members Name,
which gives the name of the class and FullName which is the name preceded with the name of
the Namespace. When we use int as the name of the class, the member Name does not display int
but Int32; we mentioned earlier int is an alias for a structure Int32 in the System namespace. This
is what FullName tells us. We thus have visible proof that int is an alias for a structure. yyy is
class belonging to no namespace and hence the Name and FullName members are similar.
a.cs
using System;
using System.Reflection;
class zzz
Type m = typeof(yyy);
MemberInfo [] n;
n = m.GetMembers();
Console.WriteLine(n.Length);
foreach ( MemberInfo a in n)
Console.WriteLine(a.Name);
class yyy {
}
Output
GetHashCode
Equals
ToString
abc
GetType
.ctor
We are now displaying the members of a class yyy. The class Type has a function called
GetMembers that returns an array of type MemberInfo. Every array has a field called Length that
returns the size of the array. In our specific case it is 6. We then use a foreach to run through each
member of the MemberInfo array and are displaying the name of each function using the field
Name from the class MemberInfo.
a.cs
using System;
using System.Reflection;
class zzz
Type m = typeof(yyy);
MemberInfo [] n;
n = m.GetMembers();
Console.WriteLine(n.Length);
foreach ( MemberInfo a in n)
{
class yyy {
public int i;
Output
Int32 i yyy
The first concept you need to be clear with is that we can inspect only details of public members
and protected or private like pqr and xyz. Also variables are part of the members of a class. The
MemberInfo object has a ToString function that displays the entire function in all its glory
including parameters and their data types. The names of the parameter variables are however not
being displayed. The DeclaringType member returns the class name that the member belongs to.
Thus we can differentiate which class created the function.
a.cs
using System.Runtime.InteropServices;
using System;
using System.Reflection;
class zzz
Type m;
m = typeof(yyy);
System.Console.WriteLine(m.Name);
Console.WriteLine(a);
[AttributeUsage(AttributeTargets.All)]
s1=s;i1=i;
set { s2 = value; }
class yyy
public int i;
Output
yyy
GetCustomAttributes takes a boolean as parameter and returns an array of objects. The ToString
function of the attribute class gets called which will decide what string the attribute stands for.
a.cs
using System.Runtime.InteropServices;
using System;
using System.Reflection;
class zzz
Type m;
m = typeof(yyy);
System.Console.WriteLine(m.Name);
foreach(MethodInfo a in m.GetMethods())
object [] b = a.GetCustomAttributes(true);
foreach(Attribute c in b)
Console.WriteLine(c);
}
}
[AttributeUsage(AttributeTargets.All)]
s1=s;i1=i;
set { s2 = value; }
class yyy
{
[vijay("hi2",100, sonal = "bye2",mukhi = 2000 )]
Output
yyy
The object m looks like Type. As explained earlier, we are calling a function called GetMethods
which returns an array of MethodInfo's. a loops through each one. We have two methods and the
foreach gets executed twice. Once for abc and then for pqr. The GetCustomAttributes also exists
in a MethodInfo class that returns an array of objects representing our attributes. We iterate
through each, displaying what the ToString function returns. As we have only one attribute per
function, the second for each gets executed only once.
a.cs
using System.Runtime.InteropServices;
using System;
using System.Reflection;
class zzz
Type m;
m = typeof(yyy);
System.Console.WriteLine(m.Name);
foreach(MethodInfo a in m.GetMethods())
object [] b = a.GetCustomAttributes(true);
foreach(Attribute c in b)
if ( c is vijay )
Console.WriteLine(c);
[AttributeUsage(AttributeTargets.All)]
s1=s;i1=i;
}
set { s2 = value; }
class yyy
There is no change at all in the output. A function can be decorated with as many attributes as
you like. We would like to filter out certain attributes.
a.cs
using System.Runtime.InteropServices;
using System;
using System.Reflection;
class zzz
Type m;
m = typeof(yyy);
System.Console.WriteLine(m.Name);
foreach(MethodInfo a in m.GetMethods())
object [] b = a.GetCustomAttributes(true);
foreach(Attribute c in b)
if ( c is vijay )
Console.WriteLine(c);
return "vijay";
return "vijay";
class yyy
[vijay()]
[vijay()]
[vijay1()]
Output
yyy
vijay
vijay
We have two attribute classes vijay and vijay1. The function pqr has been decorated with 2
attributes whereas abc with only one. However we do not see vijay1 in the output as the 'c is
vijay' makes the if statement true only for the attribute vijay and not vijay1. For the function pqr
GetCustomAttributes returns an array of size two, but the if statement is true only for one of
them, the one with the attribute name vijay. This is because of the 'is'.
a.cs
using System;
class zzz
if ( a is yyy)
Console.WriteLine("a yyy");
if ( b is xxx)
Console.WriteLine("b xxx");
if ( b is yyy)
Console.WriteLine("b yyy");
int d = 10;
if ( d is yyy)
Console.WriteLine("b yyy");
class xxx
}
Output
a yyy
b xxx
b yyy
We would like to know the data type of an object at runtime. C# offers you a keyword 'is' that
lets you check the data type of an object. a looks like yyy and 'is' results in true. B looks like xxx
but is initialized to a new yyy. Thus it doubles up for a yyy and a xxx resulting in the next two
is's returning true. D is an int and not a yyy, so the last 'is' is false.
Attributes Revisited
Positional parameters are a must whereas names parameters are optional. Attribute parameters
can be a bool, byte, char, short, int, long, float and double. These are the simple types that C#
supports. Other data types are string, enums, objects arrays etc.
Attribute usage has a position parameter which specifies the elements where the attribute can be
used. The default is All. It also has one named parameter called AllowMultiple.
a.cs
using System.Runtime.InteropServices;
using System;
class zzz
[AttributeUsage(AttributeTargets.All)]
{
public vijay(string s)
class yyy
[vijay("hi")][vijay("hi1")]
Compiler Error
a.cs
using System.Runtime.InteropServices;
using System;
class zzz
[AttributeUsage(AttributeTargets.All,AllowMultiple=true)]
public vijay(string s)
class yyy
[vijay("hi")][vijay("hi1")]
[vijay("hi2") , vijay("hi3")]
We get no error as by default the AllowMultiple named parameter has a value of false. If we set
its value to true, we are allowed to use multiple attributes on any entity. The above two forms are
similar and either one can be used. Attribute permits us to set declarative information for various
program entities for use by someone else at run time.
Conditionals
a.cs
using System.Diagnostics;
using System;
class zzz
a.abc();
}
class yyy
[Conditional("vijay")]
Console.WriteLine("abc");
When we run the above program we get no output at all. In other words the function abc does not
get called at all. This is inspite of writing a.abc().
a.cs
#define vijay
using System.Diagnostics;
using System;
class zzz
a.abc();
}
class yyy
[Conditional("vijay")]
Console.WriteLine("abc");
Output
abc
Any line beginning with a # is read by the C# pre-processor, a program that starts before the C#
compiler starts. It has words like #define which creates a variable or word called vijay. In a
programming language, a variable has to have a value, but in the preprocessor scheme of things,
it may/maynot have a value. However if we do not give it a value, like in this case, the variable is
only set to have been defined or created. Anything in [] brackets is an Attribute class. Earlier we
had not created a variable vijay and hence the entire code of abc was left out of the executable
file. Not only that, but all calls to function abc were eliminated from our code. All of this by
defining or not defining a variable vijay. This is what we passed as the attribute to Conditional.
We can create functions that are omitted during compilation depending upon a preprocessing
symbol.
When we write code, we add a lot of code for debugging purposes. This code is to help the
programmer debug code. After a function works, it is error free, we do not require any of this
debugging code. One way to eliminate this debugging code is by making the functions
conditional. The resulting code is called a 'Retail build' and the debugging version, obviously a
'Debug build'. A Retail build is much smaller in size and obviously much faster. The #define has
to be at the start of code.
Another way of achieving the same result is by eliminating the #define from the code and
creating a preprocessor symbol as an option to the compiler.
The compiler option is /d and the colon is part of the syntax. Following the colon is the name of
the preprocessor symbol. In this case, it is vijay. We’ve discussed preprocessors in one of the
earlier chapters.
a.cs
using System;
class zzz
a.abc();
class yyy
[Obsolete]
Console.WriteLine("abc");
Compiler Error
Output
abc
Many a times we create functions in a class which we would not want the user to use, as these
functions were useful years ago, but are now obsolete. The only way to warn the user that some
time in the future we will no longer support these functions is by marking them with the attribute
Obsolete. We see the warning as displayed above but the program runs as normal.
15
Unsafe code
Today, the programming language C is the most widely used because of only one reason and that
is the use of pointers. In this chapter, we will explain what pointers are all about and how they
can be used in the world of C#.
a.cs
class zzz
a.abc();
class yyy
int *i;
Compiler Error
All simple variables like int, byte, short store numbers. When we create a variable in C#, we are
allowed to put a multiplication/asterisk sign '*' in front of the variable. These variables are called
Pointers. We get an error as C# considers pointers to be unsafe and hence we need special
permission to use pointers.
a.cs
class zzz
a.abc();
class yyy
int *i;
}
}
Compiler Error
a.cs(11,20): error CS0227: Unsafe code may only appear if compiling with /unsafe
As seen in the previous chapter, the unsafe option must be tagged while compiling the program.
Give the command as csc a.cs /unsafe and the error now disappears.
a.cs
class zzz
a.abc();
int *i;
The C# documentation very clearly states that the modifier can be used along with the class
keyword, By using the modifier unsafe, we are asking C# to let us use pointers as we are unable
to write code without the use of pointers.
a.cs
using System;
class zzz
a.abc();
class yyy
Console.WriteLine(sizeof(byte *) + " " + sizeof(short *) + " " + sizeof(int *) + " " + sizeof(long
*));
Console.WriteLine(sizeof(byte **) + " " + sizeof(short **) + " " + sizeof(int **) + " " +
sizeof(long **));
Output
4444
4444
Some time back, we had used the sizeof keyword, to determine how much memory C# allocates
for our variables. When we ask for the sizeof an pointer variable, we always get 4, irrespective of
whether the data type is a short or int or whatever, including another pointer.
a.cs
using System;
class zzz {
a.abc();
class yyy {
int *i;
int j=1;
i = &j;
Console.WriteLine((int)i);
*i = 10;
Console.WriteLine(j);
Output
1243472
10
We have created a variable j that has been initialized to one. We have also created a variable i,
with a multiplication sign at the time of creation. By doing this C# allocated four memory
locations to store i. What is most important is that a pointer variable is just like any another
variable. It simply stores numbers. The single big difference is that a pointer variable value is
interpreted as a computer memory location. If both i and j were being initialized to 1, then j is the
number 1 as we know it, whereas i stand for computer memory location 1. Pointers can only be
initialized to a computer memory location. Whenever we place an ampersand(&) in front of a
variable, we are asking C# to tell us about the memory allocated for the variable. Every time C#
creates a variable, it stores it somewhere in memory. We are at times interested in knowing where
in memory the variable was allocated. A & in front of j will tell us the memory location where j
starts in memory. As it is a computer memory location or address we can store it in i. C#
allocated 4 memory location for j and the start of these 4 are being stored in a pointer.
We would like to display the value of the pointer. The WriteLine function does not have an
overload to display a pointer and we have to cast it to an int. As we get 1243472 displayed, it
could only mean that the variable j begins here and is spread over memory locations 1243473,
1243474 and 1243475.
We can only place the multiplication sign in front of a variable defined to be a pointer. If i is not
a pointer, *i will return an error. C# here asks a simple question. What is the value of the variable
i? . The answer is 1243472. C# will now go to memory location 1243472 to 1243475 and place
the value 10 there. As the value of j is determined by what is present from memory locations
1243472 to 1243475, the value of j changes from 1 to 10.
a.cs
using System;
class zzz
a.abc();
class yyy
int *i;
int j=1, k = 1;
i = &j;
Console.WriteLine((int)i);
*i = 10;
Console.WriteLine(j);
i = &k;
Console.WriteLine((int)i);
*i = 100;
Console.WriteLine(k + " " + j);
Output
1243468
10
1243464
100 10
Whenever we create a pointer variable, int *i, we are not stating explicitly which int i will be
pointing to. Thus it can point to one int today, another int tomorrow. This is what gives pointers
their flexibility. It can point to any int it wants to in memory. We are first initializing i to point to
j, then we are changing the value of j to 10 through the pointer. Then i points to k in memory, and
then k's value is indirectly being changed to 100 through the pointer. The first WriteLine tells us
that the variable j begins at memory location 1243468. From here the next 4 have been reserved
for the variable j. Memory for k has been allocated at 1243464. Thus, physically, k starts first in
memory from 1243464 to 67 and j from 1243468 onwards.
a.cs
using System;
class zzz
a.abc();
}
class yyy
int *i;
int j=1;
i = &j;
Output
1243464 1243468
Lets not forget that pointers are also variables and C# allocates memory for i. An & in front of
any variable tells us where it starts in memory. Thus i starts from memory location 1243468
onwards.
a.cs
using System;
class zzz
class yyy
long *i;
long j=1, k = 1;
i = &j;
Console.WriteLine((int)i);
i = &k;
Console.WriteLine((int)i);
Output
1243460
1243468
The sizeof a long is 8 bytes and the addresses printed differ by 8 bytes.
a.cs
using System;
class zzz
{
public static void Main()
a.abc();
class yyy {
byte *i;
byte j=1, k = 1;
i = &j;
Console.WriteLine((int)i);
i = &k;
Console.WriteLine((int)i);
Output
1243468
1243472
The only change here is that j and k are not longs but bytes. Why are we learning all about
pointers is a question you should ask yourself. The C# documentation says very clearly that a
byte occupies one memory location. The sizeof byte will also return one. In the above output,
however, the memory locations differ by 4. The reason being that on the Pentium Processor, if
we want one memory location, we will receive a minimum of 4. That's why, the Pentium is said
to be a 32-bit processor. It will give you memory in chunks of 4. From this knowledge, using a
byte instead of a int does not conserve memory or speed up your program. The above
explanation cannot be comprehended without the knowledge of pointers.
a.cs
using System;
class zzz
a.abc();
class yyy
byte *i;
i = 0;
Console.WriteLine((int)i);
Compiler Error
C# is a strongly typed language and we are not allowed to convert a zero which is an int to a byte
*, the data type of i. The only way out is to use a cast.
a.cs
using System;
class zzz
a.abc();
class yyy
Console.WriteLine((int)i + " " + (int) j + " " + (int) k + " " + (int)l);
i++;j++;k++;l++;
Console.WriteLine((int)i + " " + (int) j + " " + (int) k + " " + (int)l);
i++;j++;k++;l++;
Console.WriteLine((int)i + " " + (int) j + " " + (int) k + " " + (int)l);
Output
0000
1248
2 4 8 16
A pointer to any data type is allocated four memory locations at the time of creation. This
enables pointers to store values that range from 0 to 4 billion. The question that comes to your
mind, is what is the difference between a pointer to an int from a pointer to a long. We have
created four variables i, j, k, l. Each is a pointer to a different data type. We have also initialized
each variable to 0 and displayed their values using the WriteLine function. We have then
incremented each of them by 1. To our surprise the pointer to an int k, increases by 4 and not by
1. The char pointer increases by 2 and long by 8. To make sure that is not a isolated phenomena,
we increment them again. Same answer once again. They do not increase by one but by the size
of the data type they point to. The sizeof a long is 8 and thus a pointer to a long increases by 8
and not 1.
When we initialized l to zero, we were telling C# that a long begins at memory location 0. This
long will occupy the next 8 memory locations, form 0 to 7. Thus when we write l++, we are
telling C# to take us to the next long in memory, which has to begins now at 8. The first
difference between pointers to different data types is that the amount the pointer value increases
is dependent upon what it is pointing to.
a.cs
using System;
class zzz
a.abc();
class yyy
{
unsafe public void pqr(int x , int y , int z)
*p1 = 20;
*p2 = 30;
int l=1,m=2,n=3;
pqr(l,m,n);
Output
123
We have created a variable i of type int in memory. It begins at memory location 1243460.
Similarly m and n start at 56 and 52 respectively. We are then calling a function pqr and passing
three parameters to it. These are being stored at memory locations 1243424, 36 and 32
respectively. When we write *p1, we are going to memory location 1243424 and writing 20
there. This will change the value of x from 1 to 20. As variable l begins at 1243460, its value
remains unchanged. The area of memory where x, y and z start is called the stack. Stack memory
is used to pass parameters to functions.
a.cs
using System;
class zzz
a.abc();
class yyy
int l=1,m=2,n=3;
pqr(l,m,n);
xyz(l,m,n);
Output
Now you will begin to comprehend the importance of pointers. Its is an understanding of
pointers that will give you a better insight into understanding the innards of a programming
language. The last two WriteLines display the same answer as the stack memory gets reused for
every function call. The stack is an area of memory that will store parameters and variables
created in a function. Let us assume that the stack begins at memory location 100. The
parameters are first pushed onto the stack and then all the local variables are created later, but
below the parameters. Remember that the stack grows down in memory. When the function is
over, the stack is moved back to 100, and the next function that gets called, reuses the same
memory from 100. Thus anything created in a function has a lifetime of the open and close
braces as the next function uses the same memory and the earlier values get overwritten.
a.cs
using System;
class zzz
a.abc();
class yyy
int i=0,j=0,k=0;
int x=0,y=0,z=0;
int i=0,j=0,k=0;
pqr();
xyz();
aaa();
Output
The above program proves a number of points. C# reuses the same memory for passing
parameters and creating variables in functions. The variable names are not important as they get
created on the stack, at the same place in memory.
a.cs
using System;
class zzz
a.abc();
class yyy
p3++;p3++;p3++;p3++;p3++;p3++;
Console.WriteLine((int) p3);
*p3=20;
p3++;
Console.WriteLine((int) p3);
*p3=200;
}
unsafe public void abc()
int l=1,m=2,n=3;
pqr(l,m,n);
Output
1243452
1243456
1 200 20
Pointers are really unsafe. There is a simple rule in C# which says that variables created in one
function abc, cannot be changed by another function pqr. The variables m and n begin at memory
locations 1243456 1243452 respectively. If there was some way, I could write to these memory
locations, I would be changing the values of m and n respectively. The pointer p3 stores, where
the parameter z is stored in memory i.e. 1243432. If we can increment this pointer 6 times, 6 will
actually be 24 due to pointer arithmetic, the value of p will now be 1243452 which is the address
of n in memory. Thus from one function, I can change the value of another variable. In this case
we are doing it on purpose but if I called a function, where a pointer went haywire, my variables
change and nobody knows why the program stops working. Thus pointers are like a sharp knife,
it can save a life in the hands of a doctor but in the wrong hands it can also kill.
a.cs
using System;
class zzz
a.abc();
class yyy
int q = 1;
while ( q <= 12 )
p1++;
q++;
}
unsafe public void abc()
int l=1,m=2,n=3;
pqr(l,m,n);
Output
1243428 47645012
1243432 3
1243436 2
1243440 0
1243444 1243508
1243448 1243544
1243452 3
1243456 2
1243460 1
1243464 1243452
1243468 1243460
1243472 1243484
123
Would it not be a great idea to be able to display whatever is there on the stack. Between
variables there are some gaps and the above program is displaying the contents of the stack. The
variable q makes the loop go on 12 times and each time we increment p1 by 4. P1 is pointing to x
the first parameter on the stack. Would it not aid understanding if Microsoft explained what all it
pushes on the stack. One of the most common hacking exploits on the net is called a stack
overflow.
a.cs
using System;
class zzz
a.abc();
pqr(a);
Compiler Error
a.cs(20,1): error CS1502: The best overloaded method match for 'yyy.pqr(int*)' has some invalid
arguments
a.cs(20,5): error CS1503: Argument '1': cannot convert from 'int[]' to 'int*'
We were trying to pass an array as a parameter to a function. Unfortunately C# has some other
views.
a.cs
using System;
class zzz
a.abc();
{
unsafe public void pqr( int *a)
Output
10 2 30
The keyword fixed removed the error. An array in memory can be moved around by C#. We
would like C# to keep it fixed in memory. The keyword fixed guarantees that C# will not move it
around in RAM for the duration of the program. The only reason C# moves objects in memory is
to speed up execution of the program. The keyword fixed as part of syntax wants the () .Within
them you can create a variable in our case i which we initialize to a C# object, an array a. The
scope or lifetime of this array is in the next statement i.e. the invocation of function pqr. In case
you have more lines you can use the {}. Even though a now is a pointer to an int, the notation
a[0] refers to the first member. The name of an array tells us where the array starts in memory.
a.cs
using System;
class zzz
{
yyy a = new yyy();
a.abc();
Output
10 2 30
100 40 33
Changing anything through a pointer changes the original. Whenever we write a[1]= , we are
changing the first member of the original array. a[1] is only a notation, it actually get converted
to *(a+1). Thus we are changing the original members of the array. Also the array grows upward
in memory.
a.cs
using System;
class zzz
a.abc();
*(a+i) = i*10;
Please do not run the above program as the error would be unpredictable. The reason being that
we are writing beyond the bounds of the array. The array a created in the function abc has only
12 memory locations allocated for it. We are writing the next 2000 * 4, 8000 memory locations.
The error on your machine will be very different form another machine. This unpredictability is
why pointer errors are hard to catch, and your boss would thus not like you to use a pointer while
programming.
a.cs
using System;
class zzz
a.abc();
struct aaa
class yyy
{
unsafe public void abc()
aaa *a;aaa b;
b = new aaa();
a = (aaa *)b;
Compiler Error
aaa is a structure with two members i and j. new aaa() allocates memory for i and j. new aaa()
and b are of the same data type ie aaa. When we try to equate a and b, C# canot convert a pointer
to a struct/class to the object itself. Remember new returns not a pointer to an object but the
object itself.
a.cs
using System;
class zzz
a.abc();
struct aaa
{
public int i,j;
class yyy
aaa *a;aaa b;
b = new aaa();
a = &b;
int *x;
x = &(a->i);
int *y;
y = &(a->j);
Output
We need to take the address of where b begins in memory by using the & and equate that to a.
The address of an object like aaa is of the data type aaa *. As a now is a pointer to a structure, we
have to use a different syntax to display the members of the structure. The new way is to use the
-> operator. Thus a->i refers to the member i of the structure that looks like aaa. The variable x
now stores the address of where the first member i begins in memory. Obviously the address of
the first member i and the address of the structure will be the same and the second member will
be stored 4 later.
a.cs
using System;
class zzz
a.abc();
struct aaa
class yyy
aaa *a;aaa b;
b = new aaa();
a = &b;
Console.WriteLine((int) a);
b = new aaa();
a = &b;
Console.WriteLine((int) a);
Output
1243468
1243468
We have one object b that we have initialized twice with new. Each time we get the same
memory location as the address of b in memory will remain the same.
Unions
a.cs
using System.Runtime.InteropServices;
class zzz
a.i = 65536+512+3;
System.Console.WriteLine(sizeof(yyy));
}
[StructLayout(LayoutKind.Explicit)]
struct yyy
Output
66051 515 3
Let us understand what a union is all about. We are printing the addresses of i, j and k and lo and
behold they are all the same. In a union all the members begin at the same place and that is why
their addresses were similar. If we understand pointers, understanding unions then becomes a
piece of cake as we can visually see the addresses.
a.cs
using System.Runtime.InteropServices;
class zzz
a.i = 65536+512+3;
System.Console.WriteLine(sizeof(yyy));
[StructLayout(LayoutKind.Explicit)]
struct yyy
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public short j;
[FieldOffset(10)]
public byte k;
Output
66051 515 0
a.cs
using System;
class zzz
a.abc();
class yyy
short i = 512+3;
byte *j;
j = (byte *)&i;
*j = 1;
Console.WriteLine(i);
j++;
Console.WriteLine((int)j);
*j=1;
Console.WriteLine(i);
j++;
Console.WriteLine((int)j);
*j=10;
Console.WriteLine(i);
Output
1243468 515
513
1243469
257
1243470
257
j is a pointer to a byte. From the output, we can see that i begins at 1243468. i is of data type
short which means it takes 2 bytes. j now contains the the address value of i i.e. 1243468. The
first line proves it. The statement *j=1 will change the bottom byte value to 1.j++ will then
increment the address value by 1, hence *j=1 will now change the top byte to 1. The last j++ has
no effect because the scope of short is only 2 btes. Hence we see no change in the value of i.
a.cs
using System;
class zzz {
a.abc();
class yyy {
int i = 512+3;
byte *j;
j = (byte *)&i;
*j = 1;
Console.WriteLine(i);
j++;
Console.WriteLine((int)j);
*j=1;
Console.WriteLine(i);
j++;
Console.WriteLine((int)j);
*j=10;
Console.WriteLine(i);
Output
1243468 515
513
1243469
257
1243470
655617
The last j++ in the series will touch the third byte, there by replacing the 1 to 10. Hence the
output changes dramatically.