-4-

 

Classes

 

In the earlier chapters, we had exploited the existing C# classes like String and int, which were utilized to display text and values. In this chapter, we shall focus on creating our own classes.

 

a.aspx

<%@ Inherits="zzz" Src="b1.cs" language=C# %>

 

b1.cs

public class zzz

{

}

 

Output

Parser Error Message: 'zzz' is not a valid base class because it does not extend class 'System.Web.UI.Page'.

 

So far, we have learnt about the 'language' attribute with the ASP directive, which is used to specify the programming language that we shall be using in the file. The 'language' attribute was initialized to C#, thereby signifying that the rules of C# will be applicable on the code inserted with the aspx tags.

 

We now introduce two more attributes in addition to the 'language' directive.

     inherits - This attribute requires the name of a class and hence, we have provided the name zzz.

     src - This attribute is initialized to b1.cs, which is a program file that contains the class.

 

A class is a collection of variables and methods, which have been bunched together. It can therefore be considered as a container of things.

 

The file b1.cs is a C# file which contains the syntax 'public class zzz', followed by a pair of curly braces. The keyword 'class' results in the creation of a class called zzz. The curly braces signify the beginning and end of a class. Currently, the class that we have created does not contain any variables or methods.

 

Thus, we can conclude that the integer class was created through the syntax 'class int', while the string class was created through the use of the syntax 'class string'. There is no other procedure available, to create a class. The rules that apply to one class are common to the rest of the classes in C#. All the code in the C# language is contained in classes only.

 

In the above program, an error is generated, since ASP+ does not expect an empty class. It expects the class to contain variables and functions that it needs to invoke. However, they are not currently present in the class. Since there is a paucity of time, and moreover, due to lack of  perseverance that is vital for writing all this code ourselves, we shall borrow code from an existing class that contains the relevant functions and variables.

 

To inherit or borrow from another class, we have to make one small amendment to the source code in the file b1.cs.

 

b1.cs

public class zzz : System.Web.UI.Page

{

}

 

There exists a free class called System.Web.UI.Page that has been written by the programmers at Microsoft. This class has all the functions that ASP+ requires. To inherit or borrow from an existing class, we are required to place a colon : after the name of the class (as in zzz), and then specify the class that we want to inherit from, i.e.  System.Web.UI.Page. You may have noticed that, for the Page class, the name System.Web.UI.Page is an extended one. We shall look into the reasons for the same, a little later.

 

Technically, we can say that the class zzz derives from class Page. This implies that all the methods and variables of class Page are now available to class zzz also. In a sense, it is akin to writing all the methods and variables in the zzz class, by ourselves. When we derive from the class Page, whatever is contained in the class, also exists in the derived class zzz, making it a rich class.

 

The word 'public', which precedes the class name, is an access modifier. Access modifiers are used to restrict access to a class, since it may not be desirable to allow everyone to access the class. The access modifier 'public' facilitates anyone and everyone to access the class. On making these changes to the source code, no errors are generated when we run our program.

 

a.aspx

<%@ Inherits="zzz" Src="b1.cs" language=C# %>

<form action="a.aspx" runat="server">

<asp:button type=submit text="Click" OnClick="abc" runat="server"/>

</form>

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object a, System.EventArgs e)

{

Response.Write("hi");

}

}

 

After every click on the button, you will see the word 'hi' displayed. Let us now understand how the button works. Each time we click on a button, the function abc is called, since it is associated with the attribute OnClick.

You will not notice words such as, 'script' in the aspx file because the function code is not present in a.aspx. It is located in the class zzz, which is present within the src file named b1.cs. As you must have noticed, this function resides within the class zzz.

 

The 'inherits' attribute makes the code, which is present in the class zzz of the file b1.cs, accessible to the aspx file. Now, the function abc does not generate any error, since it meets its match and displays 'hi' in the browser window.

 

This is fascinating because it demonstrates that all the code within a C# file, can now be used with ASP+. So, let us now expand our horizons about the basics of C# programming. We shall leave a.aspx untouched for a long while, and modify the file b1.cs progressively, to explain certain issues related to the C# programming language.

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object o, System.EventArgs e)

{

yyy a;

}

}

 

Output

Compiler Error Message: CS0246: The type or namespace name 'yyy' could not be found (are you missing a using directive or an assembly reference?)

 

In b1.cs, we are trying to create an object 'a', that is an instance of a class yyy. But, the output displays an error, stating that C# is unaware of the class yyy.

 

The occurrence of this error is understandable, because C# may be well informed about, and familiar with classes such as Page and a vast number of built-in classes, but it definitely is not familiar with a user-defined class called yyy.

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object o, System.EventArgs e)

{

yyy a;

}

}

public class yyy

{

}

 

You may be able to recall what we had mentioned a little while ago, that, the only way to create a class is by using the keyword 'class', followed by the class name. It cannot get simpler than this. Thus, no more errors are generated.

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object o, System.EventArgs e)

{

yyy a;

a.pqr();

}

}

public class yyy

{

public void pqr()

{

Response.Write("hell");

}

}

 

Output

Compiler Error Message: CS0165: Use of unassigned local variable 'a'

 

It is not a child's play to learn a programming language, especially when it also entails deciphering cryptic errors. What does the error message 'unassigned local variable' signify? If you may recall, in chapter 2, we had created a variable i of type int, and called the ToString function off it. In a similar manner, we have now created a variable a of type yyy and have called the function pqr off it. So, why is it that an error is generated now, while it was not generated in the earlier instance?

 

The answer lies in the manner in which C# works internally. It divides all the classes it recognizes, into two types, i.e. value types and reference types. Classes like int, bool and string, which are called basic classes, are of value type, and all the other classes are of reference type.

 

A value type variable is created when we declare it. This means that i comes into existence and occupies memory space when we declare it, using the syntax 'int i'. No extra code has to be added after that, to create this.

 

In the case of a reference type variable, C# is first informed about the data type of the variable that we want to create, and also the variable name that we would use to reference it. This happens when we use the statement yyy a. In the next round, the keyword 'new' or a function has to be used to formerly bring the variable into existence, and then it is to be assigned a memory location, to enable it to reference members of the specified data type.

 

Note, that unless the second step is executed, the members in the class remain inaccessible to the object.

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object o, System.EventArgs e)

{

yyy a;

a = new yyy();

a.pqr();

}

}

public class yyy

{

public void pqr(){

}

}

No errors are visible any longer. It is because we have used the keyword 'new' to create an object 'a', which looks like yyy. In technical jargon, 'a' is now an instance of class yyy. Thus, the only way to create an object is, by using the keyword 'new', followed by the name of the class. Thereafter, we have to use a pair of opening and closing curly braces to encompass the actual code of the class.

 

The instance 'a' now stores the return value of 'new', which is a memory location. Henceforth, it can be used to refer to all the members in the class.

 

b1.cs

public class zzz : System.Web.UI.Page

{

public void abc(System.Object o, System.EventArgs e)

{

xxx a;

a = new xxx();

a.pqr();

}

}

public class yyy

{

public void pqr()

{

}

}

public class xxx : yyy

{

}

 

In this program, we have gone a step further. The instance 'a' looks like xxx instead of yyy, and the function pqr is called from class xxx. The class xxx is derived from class yyy, following the simple rule of placing a colon first, followed by the name of the class yyy. Thus, the class xxx inherits all members of class yyy. For the moment, the class yyy has only one function called pqr, which the class xxx 'inherits'. Therefore, even though the class xxx does not contain the function pqr, the object 'a' of type xxx can call it, which is because the class xxx inherits the same from the class yyy.

 

We need to explore the C# programming language in greater depth to be able to fully understand what ASP.NET does with the C# code written in a .cs file. In order to steer clear of clutter, we have created a sub directory called aaa in the root where we have written the following program in a file called b1.cs.

 

c:\>md aaa

c:\aaa>edit b1.cs

 

b1.cs

public class zzz

{

}

 

This program is very similar to the ones we have written earlier. The code written in a .cs file must be converted into an executable program, as the web server and the web browser are not involved here. To create an executable file, we use the command csc along with the file name. In simple terms, the command csc can be called a program which creates an executable, but in the context of the C# programming language, it is identified as the C# compiler. Thus, the command is as follows:  C:\aaa>csc b1.cs

 

Output

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 'b1.exe' does not have an entry point defined

 

The compiler reports an error, since there is no 'entry point' defined in the exe file. What is an entry point? Whenever a C# program begins execution, it starts execution from a base function. This base function is called an entry point function.

 

Here, we are getting into the details of the C# programming language, because all the code written in ASP+ is first converted into C# code and then executed.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

}

}

 

Output

hi

 

Akin to the pqr function in yyy, we have introduced a function called Main within zzz in the file b1.cs. This function calls another function named System.Console.WriteLine. System.Console.WriteLine comprises of a parameter, which is a string called 'hi'. The compiler now successfully generates 'b1.exe' in the same subdirectory, without displaying any error messages. If you run this program at the command prompt, using the command  'c:\aaa>b1', the output displayed will be the word 'hi'. This proves that Main is the base function or the entry point in any C# program.

 

You may have noticed that the System.Console.WriteLine function in a.cs program, behaves like the Response.Write function of ASP+.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

abc();

}

public void abc()

{

System.Console.WriteLine("abc");

}

}

 

Output

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

 

Despite having reiterated this concept on numerous occasions, we shall go over it once again, that 'Only an object i.e. an instance of a class, is allowed access to the members of that class'. Thus, in the above program, we are not allowed to call the function abc, since we have still not created an instance of the class zzz.

 

However, there is an exception to this rule, which we shall introduce in the next program.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

abc();

}

public static void abc()

{

System.Console.WriteLine("abc");

}

}

 

Output

hi

abc

 

We have added the keyword 'static' to the function abc. The keyword 'static' allows access to functions or variable, even though, an instance of the class wherein it is contained, has not been created. Hence, no error is generated. First the word 'hi' is displayed on the screen, which is followed by the word 'abc'.

 

We shall employ one more program to demonstrate the functionality of the keyword 'static'.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

yyy.abc();

yyy a;

a = new yyy();

a.pqr();

}

}

public class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

 

Output

hi

abc

pqr

 

In the class yyy, we have two functions:

 

     The function abc, which has the static keyword.

     The function pqr, which is non-static.

 

To summon a static function, we simply use the name of the class, followed by the function name i.e. yyy.abc. Since the function abc is static, there is no need to create an object that is an instance of the class yyy. In short, a static function is associated with a class and not with an object.

 

In the case of the function pqr, the rules get transformed completely. Since pqr is a non-static function, we have to first create an object 'a' that is an instance of class yyy, and then use the object to call the function pqr. The syntax is as follows:  a.pqr().

 

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

yyy.abc();

yyy a;

a = new yyy();

a.pqr();

}

}

namespace aaa

{

public class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

}

 

Output

Microsoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]

Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

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

b1.cs(7,1): error CS0246: The type or namespace name 'yyy' could not be found        (are you missing a using directive or an assembly reference?)

b1.cs(8,1): error CS0103: The name 'a' does not exist in the class or namespace   'zzz'

b1.cs(9,1): error CS0246: The type or namespace name 'a' could not be found (are you missing a using directive or an assembly reference?)

On adding the words 'namespace aaa' to the program, we obtain four errors. Why does this happen? The answer reveals itself in the next program.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

aaa.yyy.abc();

aaa.yyy a;

a = new aaa.yyy();

a.pqr();

}

}

namespace aaa

{

public class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

}

 

Output

hi

abc

pqr

 

The errors have disappeared. This could only be achieved by preceding the class name, i.e. yyy in Main, with the namespace aaa, and then using the dot as the delimiter. Here, aaa is called a namespace.

 

The concept of a namespace is very simple.

Let us presume that in the .NET world, there are a million functions. A programmer will go bonkers trying to recollect the names of all these functions, along with the names of their respective classes. It surely makes more sense to tidy them up by organizing them in a systematic and logical fashion?

 

All printing functions can be placed in one category, while all functions that write to a file can be placed in another category. Instead of christening this type of classification as 'categories', the C# programming language makes use of the term 'namespace'. To use a class belonging to a particular namespace, we have to use the format 'namespace.class'.

 

As our class yyy belongs to the aaa namespace, the full name of the class becomes aaa.yyy, and not merely yyy.

 

b1.cs

public class zzz {

public static void Main(){

System.Console.WriteLine("hi");

aaa.bbb.yyy.abc();

aaa.bbb.yyy a;

a = new aaa.bbb.yyy();

a.pqr();

}

}

namespace aaa{

namespace bbb{

public class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

}

}

Output

hi

abc

pqr

 

We can nest namespaces to as many levels as desired. Here, we have a primary namespace called aaa containing a secondary namespace called bbb. The full name of our class yyy therefore becomes aaa.bbb.yyy, and the static function abc can be called using aaa.bbb.yyy.abc.

 

Whenever we read an entity in C#, we read it backwards, i.e. from right to left. We have the name of the function at the right most end. This is preceded by the name of the class, and the class name is preceded by the name of the namespace.

 

In the past, whenever we had derived from System.Web.UI.Page, Page was the name of the class and System.Web.UI was the name of the namespace.

 

Similarly, in the case of Response.Write, Response is the name of a class, while Write is a static function contained in it. In the past, we had deliberately tried to shield you from these complicated and perplexing concepts. This was for the simple reason that, we believe in divulging such intricate concepts only when the time is right for them to be appreciated.

 

b1.cs

using aaa.bbb;

public class zzz

{

public static void Main()

{

System.Console.WriteLine("hi");

yyy.abc();

yyy a;

a = new yyy();

a.pqr();

}

}

namespace aaa

{

namespace bbb

{

public class yyy

{

public static void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

}

}

 

Output

hi

abc

pqr

 

It shall prove to be incredibly cumbersome if we have to write aaa.bbb.yyy, every time we want to refer to the class yyy. In order to overcome this difficulty, C# offers to us a short cut in the form of a keyword called 'using'.

 

The keyword 'using' is followed by the namespace and terminated by a semicolon. Every time a class name appears in Main, C#  replaces it with its long name, by placing the namespace in front of it.  In case of any mismatch, the error message 'namespace.class not found' is generated. The keyword 'using' is similar to shorthand. It gives you the freedom to write the name of a class without actually mentioning the namespace. At the same time, the keyword 'using' can occur as many times as you want it to, in your program.

 

Constructors

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

System.Console.WriteLine("hi");

a = new yyy();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

}

 

Output

hi

yyy

 

Here, we have performed something that is unusual and anomalous, that is to say, we have assigned the same name to the function as to the class, i.e. yyy. Whenever a function has the same name as that of the class, it is treated like a special function. It is called a constructor. A constructor is automatically called, whenever an instance of the class is created. 

 

So, the code that is to be executed when an object is created, is normally placed in the constructor. You are free to place any code in the constructor.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

System.Console.WriteLine("hi");

a = new yyy();

}

}

public class yyy

{

public void yyy()

{

System.Console.WriteLine("yyy");

}

}

 

Output

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

 

The syntax 'new yyy ()' creates an instance of the class yyy. This implies that, it internally allocates memory for the methods and the variables of the class yyy. The constructor is called, as the last action in this sequence.

 

At the time when the constructor is being executed, the object has not been created. Thus, constructors cannot return any values, because there is no object available to accept these values. The void data type signifies that there is no return value. However, in the case of constructors, there is no possibility of any value being repeated. The C# compiler assumes that yyy is a normal function because of the return type. Since a normal function cannot possess the same name as the name of the class, the above error message is generated.

 

An object is created only after the constructor finishes executing its code successfully.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

System.Console.WriteLine("hi");

a = new yyy();

a.yyy();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

}

 

Output

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

 

A constructor is a function with only two restrictions:

 

     The first is that it cannot return any values, as explained above.

     The second is that we cannot call a constructor explicitly.   It gets called automatically, only during the creation of an instance of a class.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy();

a.abc();

a.abc("hi");

a.abc(10);

}

}

public class yyy

{

public void abc()

{

System.Console.WriteLine("abc");

}

public void abc(string s)

{

System.Console.WriteLine("abc " + s);

}

public void abc(int i)

{

System.Console.WriteLine("abc "+ i);

}

}

 

Output

abc

abc hi

abc 10

 

In C#, we are allowed to create different functions having the same name, as long as they accept different number and types of parameters. We may be acquainted with a function only by its name, but C# identifies a function by using its name, as well as, through the number of its parameters along with their data types.

 

We have created three separate functions in our program using the same function i.e. abc. However, since the parameter types are different in each case, C# flags them as separate functions.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy("hi");

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

}

 

Output

b1.cs(6,5): error CS1501: No overload for method 'yyy' takes '1' arguments

A constructor is basically a function. So, all the rules of a function also apply to a constructor. Thus, in the case of yyy, we need a function/constructor that accepts a string as a parameter.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy("hi");

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy");

}

public yyy(string s)

{

System.Console.WriteLine("yyy " + s);

}

}

 

Output

yyy hi

 

To eliminate the above error, we have introduced one more constructor that takes a single string type parameter. The constructor that has more than one parameter is ignored, and the one with a single parameter is called. Thus, when we create an object using 'new', only the constructors that pre-exist in the class are called. If a constructor with a specific number of parameters, does not exist, we cannot use 'new' to create an object with those many number of parameters, because it will generate an error.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy();

}

}

public class yyy

{

public yyy(string s)

{

System.Console.WriteLine("yyy " + s);

}

}

 

Output

b1.cs(6,5): error CS1501: No overload for method 'yyy' takes '0' arguments

 

Life consists of unexpected twists and turns, which adds, in no small measure, to its excitement. Earlier, when we had not used constructors in our code, C# allowed us to use the keyword 'new' with abandon. However unexpectedly, when constructors were introduced, it raised several objections.

 

The rationale behind this is, when we have a class without any constructors, by default, the compiler introduces a constructor that has no parameters, as in public yyy() { }. This is provided to us for free. Thus, when we have no constructors in a class, we are provided with one that has no parameters.

 

But, if we explicitly introduce even a single constructor, the free constructor brought in by the compiler, is retracted. In class yyy, since we have a constructor with one parameter, the free constructor that has no parameters, is not added. Hence, the above error is generated.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy ");

}

public yyy(string s)

{

System.Console.WriteLine("yyy " + s);

}

}

 

Output

yyy

 

The only way of getting rid of the error message is by introducing a constructor that has no parameters in the class yyy.

 

b1.cs

public class zzz {

public static void Main()

{

System.Console.WriteLine("main");

yyy a;

System.Console.WriteLine("main 1");

a = new yyy();

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy ");

}

static yyy()

{

System.Console.WriteLine("yyy static");

}

}

Output

main

main 1

yyy static

yyy

 

Static constructors are always called before the non-static or instance constructors. Moreover, they get called before any member of a class can be accessed.

 

b1.cs

public class zzz

{

public static void Main()

{

System.Console.WriteLine("main");

yyy.abc();

yyy a;

System.Console.WriteLine("main 1");

}

}

public class yyy

{

public yyy()

{

System.Console.WriteLine("yyy ");

}

static yyy()

{

System.Console.WriteLine("yyy static");

}

public static void abc()

{

System.Console.WriteLine("abc");

}

}

 

Output

main

yyy static

abc

main 1

The above program demonstrates that the static constructor is called before the static function abc. As we are not creating an object that is an instance of class yyy, the non-static constructor of class yyy is never called.

 

Interfaces

 

b1.cs

public class zzz

{

public static void Main()

{

}

}

public interface yyy

{

}

 

An interface is similar to a class. It is a reserved word in the C# programming language. Since it has been used correctly from a syntactical point of view, no errors are generated.

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

}

}

public interface yyy

{

}

 

We are also permitted to declare an object that looks like an interface, yyy. No errors are generated at all. A question that vexes us, is- 'Are interfaces and classes similar?'  Do not lose sleep over this, since they are as similar to each other, as a fish is to a fowl.

 

 

 

b1.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy();

}

}

public interface yyy

{

}

 

Output

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

 

The first difference between an interface and a class is that, an interface cannot be instantiated by using the keyword 'new'. We can use 'new' only to instantiate a class and not an interface.

 

b1.cs

public class zzz : yyy

{

public static void Main()

{

zzz a;

a = new zzz();

}

}

public interface yyy

{

void abc();

}

 

Output

b1.cs(1,14): error CS0535: 'zzz' does not implement interface member 'yyy.abc()'

 

An interface can only consist of function prototypes, i.e. the function name with its parameters. Hence, yyy is an interface that contains only one function called abc, that takes no parameters and returns a void. You may have noticed that we have not used the open and close curly braces to enclose the function code. Instead, we have terminated the function with a semicolon. Class zzz is derived from the interface yyy in the usual manner, i.e. by using a colon sign. We get an error message because the code of the function abc, is not present anywhere in the class.

 

When one class derives from another class, it inherits all the functions of the base class. But when a class derives from an interface, i.e. when it implements an interface, the code for the functions in the interface, has to be explicitly specified in the class.

 

b1.cs

public class zzz : yyy

{

public static void Main()

{

zzz a;

a = new zzz();

a.abc();

}

public void abc()

{

System.Console.WriteLine("abc");

}

}

public interface yyy

{

void abc();

}

 

Output

abc

 

The error message has vanished, since we have implemented all the functions in the interface yyy. If the interface yyy has 10 functions or definitions or prototypes, we have to add the code for all these functions in the class zzz.

 

 

 

b1.cs

public class zzz : yyy,xxx

{

public static void Main()

{

zzz a;

a = new zzz();

}

public void abc()

{

System.Console.WriteLine("abc");

}

public void pqr()

{

System.Console.WriteLine("pqr");

}

}

public interface yyy

{

void abc();

}

public interface xxx

{

void pqr();

}

 

We are allowed to derive from as many interfaces as we like. This is not the case with classes.

 

In the above program, we are deriving from two interfaces, viz. yyy and xxx at the same time. All that is required to be done is, to ensure that we have added the code for functions abc and pqr, in the class zzz.

 

b1.cs

public class zzz : yyy,xxx

{

public static void Main()

{

}

}

public class yyy

{

}

public class xxx

{

}

 

Output

b1.cs(1,24): error CS0527: 'xxx' : type in interface list is not an interface

 

As we have stated earlier, we are not allowed to derive from two classes. In C#, multiple inheritance from classes is strictly prohibited.

 

a.aspx

<%@ language=C# %>

hi

<%

Respone.Write("hi");

error

%>

 

We have created a simple aspx called a.aspx, and created an error in the C# code. The reason behind doing this is that, we intend to discover the code that is generated by ASP+.

 

When we clicked on the last link called + Show Complete Compilation Source, we got the following output:

 

Output

Line 1:    //--------------------------------------------------------------

Line 2:    // <autogenerated>

Line 3:    //     This code was generated by a tool.

Line 4:    //     Runtime Version: 1.0.2914.16

Line 5:    //

Line 6:    //     Changes to this file may cause incorrect behavior and will be lost if

Line 7:    //     the code is regenerated.

Line 8:    // </autogenerated>

Line 9:    //--------------------------------------------------------------

 

Line 10:  

Line 11:   namespace ASP {

Line 12:       using System;

Line 13:       using System.Collections;

Line 14:       using System.Collections.Specialized;

Line 15:       using System.Configuration;

Line 16:       using System.Text;

Line 17:       using System.Text.RegularExpressions;

Line 18:       using System.Web;

Line 19:       using System.Web.Caching;

Line 20:       using System.Web.SessionState;

Line 21:       using System.Web.Security;

Line 22:       using System.Web.UI;

Line 23:       using System.Web.UI.WebControls;

Line 24:       using System.Web.UI.HtmlControls;

Line 25:      

Line 26:      

Line 27:       public class a_aspx : System.Web.UI.Page, System.Web.SessionState.IRequiresSessionState {

Line 28:          

Line 29:           private static System.Web.UI.AutomaticHandlerMethodInfos __autoHandlers;

Line 30:          

Line 31:           private static bool __intialized = false;

Line 32:          

Line 33:           private static System.Collections.ArrayList __fileDependencies;

Line 34:          

Line 35:           public a_aspx() {

Line 36:               System.Collections.ArrayList dependencies;

Line 37:               if ((ASP.a_aspx.__intialized == false)) {

Line 38:                   dependencies = new System.Collections.ArrayList();

Line 39:                   dependencies.Add("C:\\Inetpub\\wwwroot\\a.aspx");

Line 40:                   ASP.a_aspx.__fileDependencies = dependencies;

Line 41:                   ASP.a_aspx.__intialized = true;

Line 42:               }

Line 43:           }

Line 44:          

Line 45:           protected override System.Web.UI.AutomaticHandlerMethodInfos AutoHandlers {

Line 46:               get {

Line 47:                   return ASP.a_aspx.__autoHandlers;

Line 48:               }

Line 49:               set {

Line 50:                   ASP.a_aspx.__autoHandlers = value;

Line 51:               }

Line 52:           }

Line 53:          

Line 54:           protected System.Web.HttpApplication ApplicationInstance {

Line 55:               get {

Line 56:                   return ((System.Web.HttpApplication)(this.Context.ApplicationInstance));

Line 57:               }

Line 58:           }

Line 59:          

Line 60:           public override string TemplateSourceDirectory {

Line 61:               get {

Line 62:                   return "/";

Line 63:               }

Line 64:           }

Line 65:          

Line 66:           public override void InstantiateIn(System.Web.UI.Control control) {

Line 67:               this.__BuildControlTree(control);

Line 68:           }

Line 69:          

Line 70:           private void __BuildControlTree(System.Web.UI.Control __ctrl) {

Line 71:               __ctrl.SetRenderMethodDelegate(new System.Web.UI.RenderMethod(this.__Render__control1));

Line 72:           }

Line 73:          

Line 74:           private void __Render__control1(System.Web.UI.HtmlTextWriter __output, System.Web.UI.Control parameterContainer) {

Line 75:               __output.Write("\r\nhi\r\n");

Line 76:              

Line 77:               #line 3 "C:\Inetpub\wwwroot\a.aspx"

Line 78:              

Line 79:   Respone.Write("hi");

Line 80:   error

Line 81:  

Line 82:              

Line 83:               #line default

Line 84:           }

Line 85:          

Line 86:           protected override void FrameworkInitialize() {

Line 87:               this.FileDependencies = ASP.a_aspx.__fileDependencies;

Line 88:           }

Line 89:          

Line 90:           public override int GetTypeHashCode() {

Line 91:               return 2141278421;

Line 92:           }

Line 93:       }

Line 94:   }

Line 95:  

 

The output displayed above is the C# code generated by ASP+ in respect of our aspx file. Let us try and decipher this output with the limited knowledge of C# that we have acquired so far.

 

We begin with a series of 'using' statements that are followed by the names of the namespaces. These 'using' statements ensure that we do not have to write the namespace names anymore. The C# file generated by ASP+ has a class name called a_aspx, since 'a' is the name of our aspx file. This class is derived from System.Web.UI.Page, which means that, all the code in the Page class is now available to a_aspx. The class also implements an interface called IRequiresSessionState, which we shall touch upon, a little later.

 

The class consists of a static constructor a_aspx, which has no parameters. Amongst the other functions present in the file, the most important function is __Render__control1. We will ignore all the above code for the moment, and focus only on this function.

 

This function always gets called by ASP+. All code other than the aspx code, i.e. the code in HTML or Javascript etc., get added to this function. This function therefore, happens to be the most crucial one. It accepts two parameters:

     The first parameter is output, which is an instance of the class HtmlTextWriter in the System.Web.UI namespace. Write is a function in the class HtmlTextWriter. Hence, it can be invoked by calling  output.Write.

 

     The second parameter to __Render__control1 is parameterContainer. It is an instance of the class Control in the System.Web.UI namespace. This parameter represents a control. The HTML text 'hi' is converted into a parameter and passed to the function Write .

 

The C# functions get copied word for word, just as we had entered them. Hasn't ASP+ become more comprehensible now? We have learnt a lot about ASP+ by making errors, and then analyzing the code that was generated. We recommend the same for you.

 

Writing Components

 

One question that continues to bother us is "How does C# compile the ASP generated code?"  To understand this, we go back to our subdirectory aaa and create two files called a.cs and b.cs.

 

a.cs

public class zzz

{

public static void Main()

{

yyy a;

a = new yyy();

a.abc();

}

}

 

Output

Microsoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914] Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

 

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

a.cs(6,1): error CS0103: The name 'a' does not exist in the class or namespace 'zzz'

a.cs(7,1): error CS0246: The type or namespace name 'a' could not be found (are you missing a using directive or an assembly reference?)

 

An error is generated, since C# cannot locate the class yyy anywhere. So far, all our classes were stored in a single file called a.cs. In this program, the class yyy is present in the file b.cs.

 

b.cs

public class yyy

{

public void abc()

{

System.Console.WriteLine("abc");

}

}

 

Using the csc command, not only can we create an executable file such as a.exe, but also a dll. The acronym dll stands for Dynamic Link Library. Code that needs to be shared under Windows, comes packaged in a dll. To create a dll, we use the same csc command, but with different options. We use the following command

 

c:\aaa>csc /t:library /out:b.dll b.cs

 

The /t:library option instructs the compiler to create a library or a dll. By default, the compiler creates an exe file. Further, the /out: option allows us to assign a name to the file. Had we not assigned any name, the default name would have been b.dll, since the source file is named b.cs. Now that we have created our dll file, we simply need to inform our csc compiler to look into this file, for the code of our desired classes. Now, all that we do is, run csc as follows: 

 

c:\aaa>csc /r:b.dll a.cs

 

The /r option asks the compiler to look into b.dll for the code of those classes, that are not contained in the file a.cs. The above program will produce a file called a.exe which, when executed, will call the function abc from the class yyy. This concept is quite simple and clear-cut, don't you agree ?

 

Let us now run the following aspx file:

 

a.aspx

<%@ language=C# %>

<%

error

%>

 

We get an error message. When we click on   + Show Detailed Compiler Output:, we see the following command:

 

C:\WINNT\system32> "c:\winnt\microsoft.net\framework\v1.0.2914\csc.exe" /t:library /utf8output /R:"c:\winnt\assembly\gac\system\1.0.2411.0__b77a5c561934e089\system.dll"

/R:"c:\winnt\assembly\gac\system.xml\1.0.2411.0__b77a5c561934e089\system.xml.dll"

/R:"c:\winnt\assembly\gac\system.drawing\1.0.2411.0__b03f5f7f11d50a3a\system.drawing.dll" /R:"c:\winnt\assembly\gac\system.data\1.0.2411.0__b77a5c561934e089\system.data.dll" /R:"c:\winnt\assembly\gac\system.web.services\1.0.2411.0__b03f5f7f11d50a3a\system.web.services.dll" /R:"c:\winnt\microsoft.net\framework\v1.0.2914\mscorlib.dll" /R:"c:\winnt\assembly\gac\system.web\1.0.2411.0__b03f5f7f11d50a3a\system.web.dll" /out:"C:\WINNT\Microsoft.NET\Framework\v1.0.2914\Temporary ASP.NET Files\root\fa7064c6\2014c0f1\jhbdrf-n.dll" /debug- /optimize+  "C:\WINNT\Microsoft.NET\Framework\v1.0.2914\Temporary ASP.NET Files\root\fa7064c6\2014c0f1\jhbdrf-n.0.cs"

 

This appears quite complicated, but it is very simple to follow.

 

ASP+, by default, runs in the subdirectory of WINNT\system32. So, the C# compiler csc is invoked from this directory. Now, since csc is not located in the system32 subdirectory, the absolute path is given for the command i.e.

 

"c:\winnt\microsoft.net\framework\v1.0.2914\csc.exe"

You will also notice a large number of /R options, that direct the compiler to look into all the specified dlls for code of classes. In case we require code from a dll that is not listed above, then we are surely out of luck.

 

Thereafter, the C# compiler is instructed to create a library and not an exe file. This output file is given a dll name  by using the /out: option, and it is stored in a particular directory

 

/out:"C:\WINNT\Microsoft.NET\Framework\v1.0.2914\Temporary ASP.NET Files\root\fa7064c6\2014c0f1\ehcuumxx.dll"

 

The name assigned to the C# program is ehcuumxx.0.cs. We can physically verify these files by going to the specified subdirectories.

 

This goes on to prove that all the HTML text and the C# code that we write in an aspx file, are finally packed into a dll. When the aspx file called 'a', is loaded for the very first time, it consumes a considerable amount of time. This is because, ASP+ has to first write out the C# program, and then compile it to generate a dll. Finally, the code is executed, which results in the display of the output in the browser window. All this happens only once, and thus, it takes a very long time. But subsequently, when the same file is requested off the server, the HTML file is generated in a much speedier manner, since the dll has already been created.

 

a.aspx

<html>

<script language="C#" runat="server">

void Page_Load(Object s, EventArgs E)

{

int i = 10;

short j = 2;

j = i;

}

</script>

</body>

</html>

 

 

 

Output

Compiler Error Message: CS0029: Cannot implicitly convert type 'int' to 'short'

Line 7:  j = i;

 

We have created two variables of two different data types, namely, i as an int and j as a short. We are not allowed to equate two different data types with each other. Thus, we get an error 'cannot covert to … line 7 j=i '. C# does not support the concept of equating different data types.

 

a.aspx

<html>

<script language="C#" runat="server">

void Page_Load(Object s, EventArgs E)

{

int i = 10;

short j = 2;

j = (short)i;

}

</script>

</body>

</html>

 

The same program now shows no error, which is because we made sure that both sides of the 'equal to' sign are of the same data type. This is incorporated by means of using the round brackets, and then by mentioning the data type to which we want the other side converted. This does not change the value of i, since it is only for a short time, that we change its data type, from an int to a short. Now, since both sides of the 'equal to' sign have a short data type, we do no get any error. The above pair of () brackets, with the data type mentioned within it, is called a cast operator.

 

The next program employs user controls, as by now, we are fairly familiar with the concept of 'new'.

 

a.aspx

<%@ Register TagPrefix="vijay" TagName="mukhi" Src="a1.ascx" %>

<html>

<script language="C#" runat="server">

void Page_Load(Object s, EventArgs E)

{

Page.Controls.Add(new HtmlGenericControl("hr"));

UserControl c1 = (UserControl) LoadControl("a1.ascx");

((a1_ascx)c1).Category = "business";

Page.Controls.Add(c1);

}

</script>

</body>

</html>

 

a1.ascx

<script language="C#" runat="server">

public String aa;

public String Category

{

get

{

return aa;

}

set

{

aa = value;

}

}

</script>

<span >Sonal: <%=aa%></span>

 

Output

Sonal: business

 

Let us look at a.aspx. In the Page_Load function, we first create an HTML tag 'hr', by using 'new'. This control is then added to the list of controls, using the Add function in Page.Controls. In this manner, we can dynamically add any control or tag we like, to a page. The a1.ascx file that contains the control, is then loaded, using the LoadControl function. The result of this function is a control that is stored in an object called c1.

 

The control has a property called Category, which is initialized to business. We need to cast it to a1_ascx, since we need to convert c1, which looks like class UserControl, into an a1_ascx class.

 

Due to the Register attribute on the control file named a1.ascx, ASP+ creates a class a1_ascx that represents our control. Hence, we need to use a cast operator, because the object c1 does not contain any property called Category. We use the Add function again to add c1 to the page.