5. The Basics of C#

 

We are of the opinion that, unless you are aware of what Visual Studio.Net does backstage, you will never be comfortable using it. Therefore, we decided to devote an entire chapter in explaining the rudiments of the C# programming language. We could have requested you to refer to our voluminous books on C# programming, but we felt that it would be unfair to expect you to learn, a great deal more than is actually required. If you are already conversant with programming, you may skip this chapter. However, we recommend that you read it anyway, and give us a feedback on what impression you gain about our handiwork.

 

In order to expound the language, we will commence by creating the smallest possible form, comprising of a textbox and a button. When the user clicks on the button, our program gets executed. Close all open Solutions, and then click on File - New - Project. Select Visual C# Project as the project type, and Windows Application as the template type. We have named this application as z1, and stored it in a distinct location, i.e. c:\mukhi. Click on OK. You must ensure that the toolbox and the Properties Windows are clearly visible on the screen. From the toolbox, drag-and-drop a button and a textbox into the form. Thereafter, double click on the button, to arrive at the Code Painter, and insert the following lines of code:

 

string items;

items = "good";

textBox1.Text = items;

MessageBox.Show(items);

items = "bad";

textBox1.Text = items;

MessageBox.Show(items);

 

We have used a word called 'items', which stores a string. A string is a term used to represent a series of characters or letters of the alphabet. On the next line, 'items' has been assigned the value "good". As all string values are to be enclosed within double inverted quotes, the word "good" too is enclosed within double quotes. The Text property of the textbox named textBox1, is then initialized to items, as it contains the string literal. We iterate the same procedure for the Show function. Build and run the project. The output screen displays a textbox and a button at their respective positions.

 

When you click on the button, the word "good" will be highlighted in the textbox, as well as seen in the message box. If you click on the OK button of MessageBox, the value changes to "bad".

 

Screen 5.1

Screen 5.2

 

Thus, wherever a string can be used, it can be effortlessly substituted with words like 'items', etc. We shall term words like 'items' as variables. Thus, the variable 'items' will hold one of the two values: "good" or "bad".

 

Close the running program and select the tab window of Form1.cs, which is the Code Painter. Amend the above stated lines to the following:

 

int products;

products = 20;

MessageBox.Show(products.ToString());

products = products + 10;

MessageBox.Show(products.ToString());

 

A new variable called 'products' has been created, and since it has the word 'int' preceding it, it is capable of storing numbers only. In a sense, C# is being unequivocally apprized about the type of values that the variable would hold. The variable 'products', of data type int, shall only store a number, whereas in the earlier case, the variable 'items', of data type 'string', is permitted to store only character literals. The variable 'products' is initialized to a value of 20, and displayed in the MessageBox. Unfortunately, the Show function in MessageBox demands a string. Under such circumstances, the ToString function is used to convert a number into a string format.

 

Once the MessagBox is closed, the next statement in succession gets executed. Here, we observe an 'equal to' sign =. Any statement with an 'equal to' sign, must be read from right to left. The statement 'products + 10' on the right hand side, will evaluate to 20 + 10; thereby, adding up to a total of 30. This value is then allocated to the variable on the left hand side. Thus, the line ultimately evaluates to 'products = 30'. The MessageBox pops up, displaying this new value of 30, thereby, confirming our contention. Screen 5.3 and screen 5.4 provides ample proof of this.

 

Screen 5.3

Screen 5.4

 

Now, close the running application, and replace the code with the new one, in exactly the same manner as is shown below.

 

abc();

}

 

void abc()

{

MessageBox.Show("hi");

}

 

After inserting the above statements, ensure that the code appears analogous to what is depicted below.

 

private void button1_Click(object sender, System.EventArgs e)

{

            abc();

}

void abc()

{

            MessageBox.Show("hi");

}

}

}

 

In due course of time, we shall italicize, the freshly inserted code, in order to help you distinguish between the recently added code and the previously existing one.

 

When we run the above program and click on the button, a MessageBox is displayed with the message "hi". Let us construe as to how this was made possible. A function is a word, followed by a pair of round brackets ( ). Thus, abc is a function. The perceptible difference here is that, unlike MessageBox.Show, which is a system created function, the function abc is our handiwork.

 

To create our own function, we write the name of the function, followed by the () brackets. The data type of the return value must also precede the name of the function. Since abc does not return any value, the word 'void' has been used. Void denotes 'nothing'. The code of the function is enclosed within the curly braces {}. We have written just a single function named MessageBox.Show, which embodies the word "hi" in it.

 

When the application runs and the button is clicked, the function abc gets called, in much the same fashion as the MessageBox.Show was summoned earlier. The code of the function abc executes the MessageBox.Show function. Thus, we see a message box, with the word "hi" displayed in it.

 

Now, we shall learn to write a function that accepts parameters. The code stipulated below corroborates this concept.

 

private void button1_Click(object sender, System.EventArgs e)

{

            int i ;

            i =abc(10,30);

            MessageBox.Show(i.ToString());

}

int abc(int j, int k)

{

            return j + k;

}

 

We commence by creating a variable i, in much the same manner, as we created 'items' and 'products'.  Thereafter, on the next line, we insert a statement with the 'equal to' sign. We trust you to be able to recall the rules of the 'equal to' sign. Always evaluate the expression from right to left.

 

The right hand side calls function abc, with two parameters. In layman terms, the function abc is supplied with two values. So, the code of function abc, must be able to accept these two values. In order to effect this, two variables are created within the round brackets () of the function abc, both having a data type of int. Thus, we are calling upon C# to store the first value of 10 in the int parameter variable j, and the second value of 30 in the int parameter variable j.

 

As the function returns an int, the datatype int precedes the word abc. C# can comprehend terms such as 'return'. So, it initially evaluates the expression j+k as 10+30, and returns the result of 40 to the main program, which had called the function abc. Effectively, the 'equal to' line evaluates to 'i = 40'. Thus, the variable i is assigned the value of 40, which is displayed with the help of the MessageBox.Show function. Functions return values, employing the 'return' keyword. These return values may be of any data type.

Now, eliminate the entire newly inserted code. This will ensure that the statements in the Code Painter appear as follows:

 

private void button1_Click(object sender, System.EventArgs e)

{

}

 

It is time to revisit a few concepts. Every time a button is inserted within a form, it is assigned a name, by default. The name so assigned is 'button1' for the first button, button2 for the second button, and so on. Similarly, the first textbox is assigned the name 'textBox1', and so on.

 

Now, when we double click on the button in a form, we get transported to a certain location within the Code Painter. The lines that are displayed exactly over and below this location, are displayed above. Does this ring a bell somewhere?

 

You would realise that, we have been transported to a position, within a function. This function is named as button1_click. It does not return any value. Hence, its return value is void. It accepts two parameters:

   'sender', having a datatype of 'object'.

   'e', having a data type of 'System.EventArgs'.

 

This is analogous to int j and int k, which we had stumbled upon, earlier. The word 'private' is called an access modifier. An access modifier determines who all are eligible to access this function. We will elucidate this concept shortly.

 

Each time we click on a button named zzz for instance, C# seeks out a function named zzz_Click, and executes it. Being acquainted with these subtle concepts, enhances our understanding of the techniques and workings of Visual Studio.Net, considerably.

 

Now, open a DOS box, and create a folder called pqr, and go to this folder. Then, write the following lines of code in a file called a.cs, using any word processor or editor.

 

C:\>md pqr

C:\>cd pqr

C:\pqr>edit a.cs.

 

a.cs

static void Main()

{

}

 

We have created a function called Main, which has no return value. Hence, its return value is of type void. We will explain the term 'static' in a little while from now. At the DOS prompt, give the following command.

 

C:\pqr>Csc a.cs

 

Output

a.cs(1,1): error CS0116: A namespace does not directly contain members such as fields or methods

 

On doing so, we come across the above specified error message.

 

You may receive an error message disparate from the one displayed above; or you may even observe the error message 

 

 'csc' is not recognized as an internal or external command, operable program or batch file.

 

In such cases, ensure that you copy the file vcvars32.bat, located in C:\Program Files\Microsoft Visual Studio.NET\Vc7\bin\, into your current directory. Thereafter, execute the program.

 

C:\pqr>vcvars32

 

Run the csc command again, and ascertain that the error displayed is akin to the one depicted above. The above stated error message may make perfect sense to you; however, it is nothing but mumbo-jumbo to us. Now, modify the file a.cs, to contain code as shown below, and then, run the csc command on the file a.cs.

 

a.cs

class zzz

{

static void Main()

{

System.Console.WriteLine("hi");

}

}

 

c:\pqr>csc a.cs

c:\pqr >a

 

Output

hi

 

The csc command does not generate any error, and produces a file called a.exe. The 'dir' command for directory listing confirms this. Run this executable at the DOS prompt, and you will see the output "hi" displayed on the screen.

 

All code written in the C# programming language, must be an integral part of a 'container'; or in technospeak, it is part of a 'class'. Thus, to banish the earlier error, we placed all our code in a class called zzz. The name zzz is actually of no consequence at all. In the Main function, we have also added a function named System.Console.WriteLine, which displays the string parameter passed to it, on the screen. The function Main is always the first function to be called. Thus, when we execute the program a.exe, "hi" gets displayed on the screen. The Main function is thus, the starting point or entry point, and any code statement placed within this function, gets executed first. If this function had been assigned any other name, abc for instance, nothing at all would have got executed.

 

a.cs

class zzz

{

static void Main()

{

yyy.abc();

}

}

class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

}

 

Output

abc

 

In this program, we have appended another class called yyy, following the class zzz. The class yyy contains a function abc, whose sole business is to display "abc" on the screen. Since the function does not belong to the current class, zzz, in order to execute it, we have to specify the name of the class, followed by a dot (which acts as a separator), and finally, the name of the function. As a result, the final expression becomes yyy.abc. Thus, we find the text "abc"  displayed, at the time of executing the above program.

 

Akin to the word 'private', the word 'public' is also an access modifier. An access modifier permits or restricts access to a function. The word private allows only the members of the same class to access its functions, whereas, the word 'public' permits all other classes to call functions located within this class. Therefore, abc can be called from zzz. If we change public to private and run the compiler, using the csc command, an error message will be flashed.

 

Error

a.cs(5,1): error CS0122: 'yyy.abc()' is inaccessible due to its protection level

 

Since abc is a member of the class yyy, and as it is 'private', it forbids any outsider from accessing it. This generates an error.

 

 

 

a.cs

class zzz

{

static void Main()

{

yyy.abc();

}

}

namespace aaa

{

class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

}

}

 

If we add the term 'namespace' to aaa, it generates the following error:

 

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?)

 

If you replace yyy.abc(); with aaa.yyy.abc();, the error will disappear. In the real word, there are innumerable classes containing functions. Consequently, these classes are clubbed together, based on the similarity in the function or the task that they perform. So, classes that deal with printing are placed into one group; while those that deal with the Internet, are housed in another. Every such group is called a 'namespace'.

 

Since the class yyy has been placed in the namespace aaa, the full reference to the function is not merely abc, but aaa.yyy.abc. In other words, it is the name of the namespace, followed by the name of the class and finally, the name of the function, with each entity separated by dots. The term System.Console.WriteLine refers to the WriteLine function, within the class named Console, under the System namespace. The first entity is the namespace name. The second entity is the name of the class. And, the last entity is always the name of the function. The requirement of providing the name of the namespace, each time that the function is to be called, proves to be awfully tedious and irksome. Therefore, we use the term 'using', which eases our task.

 

a.cs

using aaa;

using System;

class zzz

{

static void Main()

{

yyy.abc();

}

}

namespace aaa

{

class yyy

{

public static void abc()

{

Console.WriteLine("abc");

}

}

}

 

Output

abc

 

 

Both, the WriteLine and abc functions do not have the namespace preceding the class. Here, the 'using' keyword handles the issue of attaching the appropriate namespace with each class. So, whenever C# encounters a function like yyy.abc, it prefixes the class name with the word that follows the 'using' keyword, before flagging an error. If a match is found with an existing namespace, no error is generated.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy.abc();

}

}

class yyy

{

public void abc()

{

Console.WriteLine("abc");

}

}

 

 

Now, let us effect a small modification, by removing the word 'static' from the function abc. On running the compiler with the command csc on the file a.cs, the following error will be generated:

 

 

Error

a.cs(6,1): error CS0120: An object reference is required for the nonstatic field, method, or property 'yyy.abc()'

 

What is the cause behind occurrence of this error generated? And, what is the significance of the word 'static'? Before we confront this volley of questions, we want you to attempt the following program:

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

a = new yyy();

a.abc();

}

}

class yyy

{

public void abc()

{

Console.WriteLine("abc");

}

}

 

Output

abc

 

By writing int i in one of the earlier program, we had created a variable i, of data type int. Instead of calling int as a data type, we shall now call it a 'class', and instead of terming i as a variable, we shall now term it as an 'object'. Thus, when we write 'yyy a', it implies that 'a' is an object of data type yyy. In C# parlance, 'a' is an 'object', which is an instance of the class 'yyy'.

 

C# has divided classes into two categories, viz. simple and complex. The class int is a simple class. Hence, there is no need to create an object that is an instance of int. All data types of the C programming language, have been converted into 'simple' classes in C#.

 

However, yyy is a 'complex' class. Hence, it requires the 'new' keyword. New results in the creation of an instance of class yyy. Therefore, the line 'a = new yyy()' results in creating a new instance of class yyy. Deletion of this line, saddles us with the following error:

 

Error

a.cs(8,1): error CS0165: Use of unassigned local variable 'a'

 

Thus, an object must be instantiated or created by using the 'new' keyword, prior to accessing the members embodied in it. Now, since the object 'a' has been initialized, a.abc() will call the function abc, off class yyy. All other member can also be accessed in a similar manner.

 

The C# purists term the 'simple' class as the 'value' class, and the 'complex' class as the 'reference' class.

 

The 'static' keyword or modifier, when used with a function, enables access to it without the need of instantiating the class. Since a static function belongs to a class, and not to an object, the name of the class must precede the static function during access. References to non-static functions require the name of the instantiated object.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

Console.WriteLine("Before");

a = new yyy();

}

}

class yyy

{

public yyy()

{

Console.WriteLine("yyy none");

}

}

 

Output

Before

yyy none

 

When we run the above program, the first WriteLine function with 'Before' gets called. Thereafter, the WriteLine function in the function yyy, within class yyy gets called, despite our not having called this function.

 

This act can be attributed to the keyword 'new'. It first allocates code for the class, then it looks for a function name that matches with the class name. If such a function exists, it gets called instantly. Thus, this function gets called at the time of creation of an object. In technical jargon, it is termed as a 'constructor'. Once the function finishes execution, the object is created.

 

 

Constructors need special handling, and cannot be called explicitly. They get called at the time of creation of an object. If we place the statement a.yyy(); after the 'new' statement in Main, it will yield the following error:

 

Error

a.cs(9,1): error CS0117: 'yyy' does not contain a definition for 'yyy'

 

Thus, any code that needs to be called at the time of creation of an object, can be placed in the constructor. The object is created only after the constructor completes execution. Constructors are not permitted to return values.

 

Thus, modifying the constructor as shown below, results in an error, as depicted below:

 

public int yyy()

{

}

 

Error

a.cs(13,12): error CS0542: 'yyy': member names cannot be the same as their enclosing type

 

Constructors are also empowered to accept parameters. This has been clearly established in the program that follows.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

Console.WriteLine("Before");

a = new yyy("hi");

}

}

class yyy

{

public yyy(string s)

{

Console.WriteLine(s);

}

}

 

Output

Before

Hi

 

 

In the above program, the keyword 'new' along with yyy is assigned the word "hi", as a parameter. This is reflected in the signature of the constructor, that contains a parameter s, of type 'string'. Thus, we can pass as many parameters to a constructor, as we desire; and can also have scores of varied constructors, co-existing in the same class. This concept has been expounded in great detail, in our books on C#.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

a = new yyy();

a.abc();

xxx x;

x = new xxx();

x.abc();

x.pqr();

}

}

class yyy

{

public void abc()

{

Console.WriteLine("abc yyy");

}

}

class xxx : yyy

{

public void pqr()

{

Console.WriteLine("pqr xxx");

}

}

 

Output

abc yyy

abc yyy

pqr xxx

 

This mammoth program evinces a few fundamental concepts about programming. The class yyy, which has one function named abc, is instantiated using 'new'; and then, the function abc is called from it.

 

Within this program, is another class named xxx. This class ends with the words : yyy. This signifies that the class xxx is allowed access to the entities existing in the class yyy. The resultant effect is that, the code contained in yyy, also belongs to class xxx. In C# parlance, class xxx 'inherits' from class yyy. Thus, the class yyy is called the 'parent' class, while the class xxx is called the 'derived' class.

 

x is instantiated to be an instance of xxx. Since the class xxx encompasses both, xxx members and yyy members, it is authorized to work with class yyy also. Thus, we are allowed to call function abc from the object x, even though the object x does not contain this function. It is an indirect reference, via class yyy. By using the concept of inheritance, code written by other programmers can be borrowed or re-used in a program, thereby, doing away with the need to re-invent the wheel every time!

 

But, what if we want to enhance the features of the function abc? In such a situation, the existing function can be overridden with a new  copy of abc, in the class xxx. In the next code block, everything remains unchanged, except the introduction of the function abc.  So, modify the class xxx as shown below:

 

class xxx : yyy

{

public void abc()

{

Console.WriteLine("abc xxx");

}

public void pqr()

{

Console.WriteLine("pqr xxx");

}

}

 

To our utter amazement, the following warnings are issued:

 

Warning

a.cs(23,13): warning CS0108: The keyword new is required on 'xxx.abc()' because it hides inherited member 'yyy.abc()'

a.cs(16,13): (Location of symbol related to previous warning)

 

To be honest, we are unable to decipher the warning message. Despite the warnings, an executable file has been created by the compiler. When we run the program, it produces the following output:

 

Output

abc yyy

abc xxx

pqr xxx

 

Thus, we are able to call the new function abc from the xxx class, albeit, with some warnings, which we shall resolve subsequently. What happens if we wish to call the function from class yyy also? This is easier said than done. We have rewritten the class xxx as follows:

class xxx : yyy

{

public void abc()

{

base.abc();

Console.WriteLine("abc xxx");

}

public void pqr()

{

Console.WriteLine("pqr xxx");

}

}

 

Output

abc yyy

abc yyy

abc xxx

pqr xxx

 

The 'base' keyword calls the function from the 'base' or the 'parent' class. Thus, we have access to the function abc in the 'base' class, at the same time, in the 'derived' class.

 

C# is very finicky about data types. The MessageBox.Show function expects only a string data type. Hence, the int data type had to be converted into a string type, using the ToString function. An error is generated when two dissimilar data types are equated to one another. The only exception to this rule arises, when a 'base' class is equated to a 'derived' class. The next example illustrates this point.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

a = new xxx();

a.abc();

}

}

class yyy

{

public void abc()

{

Console.WriteLine("abc yyy");

}

}

class xxx : yyy

{

public new void abc()

{

Console.WriteLine("abc xxx");

}

}

 

Output

abc yyy

 

We have initialized an object 'a', declared as class yyy, as an instance of the class xxx. This is permissible, since we are equating an object of a 'base' class, to that of the 'derived' class. The sole point of concern here is that, the function will always get called from the 'base' class and not from the 'derived' class.

 

The other point of interest here is that, by adding the modifier 'new', the warnings do a vanishing act. Warnings appeared, since the function in the 'derived' class had the same name as the one in the 'base' class. It has to be explicitly declared as 'new', because here, it has no relation to the function abc in the class yyy. Thus, despite the fact that two functions share the same name of abc, they are considered different, from C#'s point of view.

 

The term 'new' gets inserted by default, incase it is omitted inadvertently. Therefore, C# gives us a benign warning, and goes ahead with the generation of the exe file. At times, a warning could be more dangerous than an error. This is because, notwithstanding the fact that an exe file may have been created, there is always a possibility of a serious problem lurking around the corner.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a ;

a = new xxx();

a.abc();

}

}

class yyy

{

public virtual void abc()

{

Console.WriteLine("abc yyy");

}

}

class xxx : yyy

{

public override void abc()

{

Console.WriteLine("abc xxx");

}

}

 

Output

abc xxx

 

After incorporating two changes in the above program. The net result is that, the function abc gets called from the class xxx, and not from the class yyy, since the object is initilalized to the class xxx. The first modification is the introduction of the word 'virtual' with the function 'abc' in the base class yyy. The second modification is the replacement of the word 'new' with the modifier 'override', in the derived class xxx. The 'override' modifier is the antithesis of 'new', as it overrides the function in the base class. Therefore, unlike 'new', the function abc in class xxx, now overrides the function abc in class yyy, thereby, eschewing the creation of a new function.

 

Deletion of the modifier 'virtual' from the function abc in class yyy, generates the error that is projected below. Therefore, the modifiers 'virtual' and 'new/override', go hand in glove.

 

Error

a.cs(20,22): error CS0506: 'xxx.abc()' : cannot override inherited member 'yyy.abc()' because it is not marked virtual, abstract, or override

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy.abc();

}

}

class yyy

{

protected static void abc()

{

}

}

class xxx : yyy

{

public void pqr()

{

yyy.abc();

}

}

Error

a.cs(6,1): error CS0122: 'yyy.abc()' is inaccessible due to its protection level

 

Out of the three access modifiers, we have already touched upon two of them, viz. 'public' and 'private'. The third one, i.e. 'protected' allows only the derived classes to access a function. Therefore, the static function abc, marked as 'protected', permits only the 'derived' class xxx to access it. Apart from this, members of a class are allowed to access any other member of the same class. However, no other function, including Main, is permitted to make a reference to this function.

 

a.cs

using System;

class zzz

{

static void Main()

{

yyy a = new yyy();

a.abc(20);

}

}

class yyy

{

int i = 10;

public void abc(int i)

{

Console.WriteLine(i);

Console.WriteLine(this.i);

}

}

 

Output

20

10

 

Variables or objects that have been created within a function, are only accessible from within that function. If we create them outside a function, they are accessible across functions, and are termed as 'instance variables'. So, the variable i, which is created outside all functions, is called an 'instance variable', and it is accessible to every other function contained in the class.

 

The value of 20, assigned to the function abc, is saved in a parameter named i. In a situation like this, the parameter i is granted a higher priority, than the instance variable. Thus, i by itself, refers to the parameter i, whereas, the term this.i refers to the instance variable i. If we had named the parameter as j, then, i and this.i would have referred to the same instance variable i.  Thus, all instance variables are prefaced with the word 'this', purely as a precautionary measure.

 

The point to be accentuated here is that, the keyword 'this' prefaces only the instance variables, and not parameters or local variables, the ones that are created within a function.

 

a.cs

using System;

class zzz

{

// a Comment

/// An XML comment

static void Main()

{

}

}

 

>csc a.cs /doc:a.xml

 

a.xml

<?xml version="1.0"?>

<doc>

<assembly>

<name>a</name>

</assembly>

<members>

<member name="M:zzz.Main">

An XML comment

</member>

</members>

</doc>

 

Programmers detest documenting their code. The C# framework has toiled relentlessly, to ease this task. So, when we run the C# compiler with the switch /doc:a.xml, it generates a pure XML file named a.xml, which includes the comments that we may have added. Any line that begins with the // symbol, is called a 'comment', and is ignored by the C# compiler. However, any line beginning with the /// symbol, is part of the XML documentation.

 

Let us write a simple C# program, which would display an empty window.

 

a.cs

using System.Windows.Forms;

namespace z10

{

class Form1 : System.Windows.Forms.Form

{

static void Main()

{

Application.Run(new Form1());

}

}

}

 

Now compile the above program, and then, run the executable. Screen 5.5 is what shows up on our screen. It is a simple blank window.

 

Screen 5.5

 

In the program, class Form1 derives from class System.Windows.Forms.Form, thereby, making Form1 the derived class and System.Windows.Forms.Form the base class. In place of the full name, we could have used : Form only, since System.Windows.Forms has been provided with the 'using' keyword. But, you must be aware of the fact that, we are afflicted with occasional fits of eccentricity!

 

Then, the Run function is called from the Application object. Since no error is generated, it may be safely assumed that, the Application object must be present in the class Form, since it is not created in Form1.

 

 

You may recollect the rule wherein it is specified that, members of the 'base' class, can be used in the 'derived' class. The parameter passed to the Run function, is a new instance of the class Form1. As a result, a window is displayed as the output. What the run function achieves internally, and how it works, is none of our concern!

 

a.cs

class zzz

{

static void Main()

{

int [] a;

a = new int[5];

a[1] = 10;

a[2] = 4;

a[1]++;

System.Console.WriteLine(a[1]);

int i;

i = 1;

System.Console.WriteLine(a[i]);

i = 2;

System.Console.WriteLine(a[i]);

}

}

 

Output

11

11

4

 

Any variable with a pair of square brackets [] following it, is known as an array. An array is merely a collection of a large number of variables, which share the same name and the data type. In order to specify a size for this array, the good old 'new' statement is employed. 'New' is passed a number, representing the quantity of variables that need to be created. Thus, the array 'a' has 5 members, all belonging to the data type, int. These ints are individually named as a[0] to a[4]. The name a[5] is fallacious here, since the referencing begins from 0, and not from 1. The only difference between a normal variable and an array variable is the presence of the square brackets [].

 

Similar to a normal variable, the value contained in the array, can be incremented with the help of the short form ++. Thus, the array variable may be used in the same context as a normal variable.

 

An array can be exploited optimally, when it is in the form a[i], wherein, a is the name of the array, and i is a variable. Since the variable a[i] does not exist per se, C# begins by determining the current value of i. Assuming it to be 0, a[i] evaluates to a[0]. If i happens to be 1, the variable now evaluates to a[1], and so on. Thus, the WriteLine function displays the value of a[1] as 11. Now, changing the value of variable i to 2, will lead to renaming the variable as a[2]. Thus, despite the two WriteLine functions being passed the variable a[i], the values displayed also change, since the value of i changes.

 

Let us now pen down a small program, which demonstrates how we can execute specific portions of the code, repeatedly.

 

a.cs

class zzz

{

static void Main()

{

int i;

for ( i = 10; i <= 12 ; i++)

System.Console.WriteLine(i);

}

}

 

Output

10

11

12

 

The 'for' statement contains two semi-colons enclosed within the open and close brackets. Whatever code is placed before the first semicolon, is executed only once. Thus, the variable i is assigned a value of 10. Then, there is a condition that is placed between the two semicolons. This condition is evaluated before the loop is entered. Thereafter, it is evaluated every time the loop finishes execution. The 'for' loop will keep iterating, as long as, this condition evaluates to True. After each such iteration, the code placed between the second semicolon and the closing round bracket, is executed.

 

If the value of i is less than or equal to 12, the condition is True, and the line of code following the 'for' statement is executed. As i currently has a value of 10, the condition evaluates to True. The WriteLine function is then executed, resulting in the display of a value.

 

Once this is done, the statement between the second semi-colon and the closing bracket, is executed. In our case, the value of i is increased by 1, making it 11. The condition is executed once again, and it evaluates to True. Thus, the WriteLine function displays the value of i as 11. Again, the variable i is incremented by 1. So, its value now becomes 12, and the condition again results in True. This value of i is again displayed using the WriteLine function. Once again, the value of i  is incremented by 1, making it 13. This time, the condition evaluates to False, because 13 is not less than 12. Thus, the next line does not get executed, and the 'for' statement terminates.

 

a.cs

class zzz

{

static void Main()

{

int [] a;

a = new int[3];

int i;

for ( i = 0; i <= 2 ; i++)

a[i] = i*10;

for ( i = 0; i <= 2 ; i++)

System.Console.WriteLine(a[i]);

}

}

 

Output

0

10

20

 

In this program, we have created an array of ints. In fact, we could have created an array of any other data type too. The array is initialized to three ints, using the 'for' statement. In the first iteration, as the value of i is 0, the variable becomes a[0], and the value that it stores is 0. In the next iteration, i becomes 1. Thus, the variable a[1] is assigned the value of 10. Finally, in the last iteration, as the value of i is 2, the variable a[2] is assigned a value of 20.

 

The second 'for' statement is used, to display the values contained in the array. Thus, employing the same approach, the WriteLine function displays the values stored in the 3 elements. In short, the 'for' statement and an array, are a match made in heaven.

 

a.cs

class zzz

{

static void Main()

{

int i;

short j;

i = 10;

j = i;

}

}

 

Error

a.cs(8,5): error CS0029: Cannot implicitly convert type 'int' to 'short'

 

C# is very fussy about the data types present on the left and the right hand side of an 'equal to' sign. They are required to be the same, but with a single exception. As i and j have different data types, they cannot be equated. Thus, an error is generated, as shown above.

 

A 'short' is similar to an int, except for the fact that, it stores a smaller range of numbers than an int. If we want to equate the two variables, the only way out is, to convert the int data type into a short. To effect this, we place the name of the data type in brackets before the variable,

 

 j = (short)i;

 

We replace the last line of the earlier program, with the line stated above. So, during the execution of the above statement, the int data type becomes a short. Now, since both sides of the 'equal to' sign have the same data type, C# does not complain, and no error is generated.

 

a.cs

class zzz

{

static void Main()

{

yyy a;

a = new yyy();

a.i = 10;

System.Console.WriteLine(a.i);

}

}

class yyy

{

public int i;

}

 

Output

10

 

The above program seems repetitive, but it illustrates a fundamental point. A variable can be initialized to a value, such as a.i = 10. The value of the variable can be displayed using the WriteLine function. The salient point is that, we can accomplish only two things with a variable, set its value and get its value!

 

While assigning or retrieving the value, no code can possibly be executed. Thus, no error checks can be performed either. Now, let us endeavour to surmount this obstacle.

 

a.cs

class zzz

{

static void Main()

{

yyy a;

a = new yyy();

a.i = 10;

System.Console.WriteLine(a.i);

}

}

class yyy

{

int ii;

public int i

{

set

{

ii = value;

System.Console.WriteLine("set " + value);

}

get

{

System.Console.WriteLine("get " + ii);

return ii;

}

}

}

 

Output

set 10

get 10

10

In the above example, the code in the class zzz, remains totally unchanged. However, major changes have been effected in the class yyy. In yyy, i is declared as a variable of data type int, but with an open and close braces following it. Had it been a normal variable, it would have ended with a semi-colon. Within the brackets, two new words, 'get' and 'set' are inserted, with each of them followed by a pair of braces.

 

Each time the value of the variable is altered, the set block gets called; to be precise, the 'set accessor' is called. This accessor is provided with a free variable called 'value', which gets the value of 10 as a.i is initialized to 10. The reserved word 'value', contains the number that is then assigned to an instance variable ii.

 

While retrieving the value of the variable i, the get accessor is called. The current value contained in the variable ii, is returned. Code can now be called in these accessors. Since it is very different from the normal variables, it has been termed as a property. The class zzz is completely oblivious of these aspects, since it is unable to distinguish between a property and a variable.

 

a.cs

class zzz

{

static void Main()

{

yyy a;

a = new yyy();

a["vijay"] = 10;

System.Console.WriteLine(a["vijay"]);

}

}

class yyy

{

int ii;

public int this[string i]

{

set

{

ii = value;

System.Console.WriteLine("set " + i + " " + value);

}

get

{

System.Console.WriteLine("get " + ii);

return ii;

}

}

}

 

 

Output

set vijay 10

get 10

10

 

Arrays are of great utility, since they are a collection of similar items. In this program, we would like to work with an array, without having to create one. 'a' is an instance of the class yyy. It is not an array, since square brackets are missing. Now, despite having clearly stated that, a is an instance of class yyy, and not an array, we use the notation of

a["vijay"].

 

Class yyy has a property called 'this' with square brackets; thus, making this a unique property or an indexer. An indexer provides the look and feel of an array, despite there being none at all. The line a["vijay"] = 10, calls the set accessor with 'vijay', as a parameter to the 'this' indexer. The string 'vijay' is stored in i, and the number 10 is stored in the reserved word 'value'. The values are printed out, to ascertain the above explanation.

 

The 'get accessor' is called, when the value of the variable has to be returned. Therefore, the output displays a value of 10. i is used to figure out the array indexer, in case there are multiple indexers. The array notation may be used to hold more than one parameter. Conclusively, an indexer renders the usage of classes, much more intuitive.

 

a.cs

class zzz

{

static void Main()

{

yyy a;

a = new yyy();

}

}

interface yyy

{

}

 

Error

a.cs(6,5): error CS0144: Cannot create an instance of the abstract class or interface 'yyy'

 

The program introduces a new term called 'interface', which we shall explain shortly. An interface cannot have the keyword 'new' prefixed to it, in other words, it cannot be instantiated.

 

a.cs

class zzz

{

static void Main()

{

xxx a;

a = new xxx();

}

}

interface yyy

{

void  abc();

}

class xxx : yyy

{

}

 

Error

a.cs(13,7): error CS0535: 'xxx' does not implement interface member 'yyy.abc()'

 

We have an interface yyy, which has a function called abc. Deriving the class xxx from the interface yyy, generates the above error. To eliminate the error, we attempt the following:

 

a.cs

class zzz

{

static void Main()

{

xxx a;

a = new xxx();

a.abc();

yyy b;

b  = new xxx();

b.abc();

}

}

interface yyy

{

void abc();

}

class xxx : yyy

{

public void abc()

{

System.Console.WriteLine("abc");

}

}

 

Output

abc

abc

 

 

The above error is banished by adding the function abc in the class xxx. Thus, whenever a class derives from an interface, it must contain a body or code, for all the function names that are present in the interface. If there are 100 function names or prototypes in the interface, each one of the 100 functions, needs to be implemented in class xxx.

 

The concept of an 'interface', is very different from that of a class. A class contains a lot of free code. However, there is no code provided along with an interface. Instead, a function body is to be provided for the function prototypes, which are present in the interface for a class that derives from it. A class can be derived from multiple interfaces, but not from multiple classes. Also, an object b, of data type interface yyy, can be initialized to an instance of class xxx; but the object can then access only the members of the interface yyy, and not those of the class xxx.

 

a.cs

class zzz

{

static void Main()

{

xxx a;

a = new xxx();

a.abc();

}

}

class xxx

{

public delegate void pqr(int i);

public void pqr1(int j)

{

System.Console.WriteLine("pqr1 " + j);

}

public void abc()

{

pqr a = new pqr(pqr1);

a(100);

}

}

 

Output

pqr1 100

 

In class xxx, the function prototype of pqr specifies that, it accepts an int as a parameter, and returns void. Also, a new keyword called delegate, has been introduced. This new introduction makes pqr a 'delegate'. The function abc, which gets called from Main, creates an instance of the delegate pqr, by using the same keyword 'new'. The only difference here is that, pqr1, which is the name of a function, is provided as a parameter to it, and round brackets are used in place of the square brackets.

 

Calling the delegate function would result in an indirect call to the function pqr1. Thus, we have been able to execute a function indirectly. The next example unfurls the true powers of delegates and events.

 

a.cs

public delegate void pqr(int p);

class zzz

{

static void Main()

{

xxx a;

a = new xxx();

a.c += new pqr(a.pqr1);

a.abc();

a.c += new pqr(a.pqr2);

a.abc();

}

}

class xxx

{

public void pqr1(int j)

{

System.Console.WriteLine("pqr1 " + j);

}

public void pqr2(int j)

{

System.Console.WriteLine("pqr2 " + j);

}

public event pqr c;

public void abc()

{

c(10);

}

}

 

Output

pqr1 10

pqr1 10

pqr2 10

 

In the above program, the delegate pqr has been made a global entity. A global entity is one, which is created outside the class. In class xxx, c is a variable of data type pqr, and contains the 'event' keyword. As a consequence, c is referred to, as an event object.  In Main, we first create 'a' as an instance of class xxx. Then, we use a special notation of += to initialize it to delegate pqr. As we have seen in the earlier example, a function must be specified with a delegate. So, the address of a function pqr1 in class xxx, has been provided. 'c' is then initialized to delegate pqr. It throws no errors, since 'c' is of data type pqr. When the abc function is called, it calls the event c. Observe the use of open and close round brackets, while an event is being called. The event, in turn, calls the function pqr1, with a parameter of 10.

 

So, what is the remarkable achievement here? In the next line, the same += is repeated, but with a new function named pqr2, as a parameter to a delegate. Therefore, when we execute the two functions pqr1 and pqr2, both the functions get called, since we have added pqr2 to the current event. Thus, the event object keeps track of all the functions that need to be called, whenever the event occurs. As a consequence, it relieves us of carrying out the above housekeeping tasks.