Sei sulla pagina 1di 394

Documents downloaded from www.funducode.com

Article: .C# - The whole new way of programming

If you are a C++ or a Java programmer you would find lot of things similar when you take a first look at C# code. However, apart from the initial similarity you will find C# a lot easier than C++ and Java. It offers simplicity of Visual Basic, power of C++ and platform independence of Java, all bundled into one language. The highlighting features of C# are as follows:

a. Full support for object-oriented programming

b. In-built support for automatic generation of XML documentation.

c. Automatic cleanup of dynamically created memory.

d. Access to .Net class library as well as Windows API.

e. Can be used to create a ASP.Net dynamic web pages.

Most of these features are available on VB.Net as well as VC++.Net. However, since C# is designed from the start to work with .Net, it uses .Net features with ease and efficiency that would be found wanting in VB.Net and VC++.Net.

C# has been developed by a team led by Anders Hejlsberg who was also the leader of the J++ team. Hence you will find the design and syntax of C# much similar to Java. However, as of now Java has one strong advantage over C#-platform independence. The same Java code can be executed on any platform that has a Java Runtime (JVM) implementation. Since JVM's are already in existence for most major platforms Java is truly portable today. Same is not true about C#-at least not as of now. In contrast, C# has two advantages over Java. These are as under:

a. C# supports operator overloading. If required C# programs can use pointers by enclosing them within 'unsafe' blocks.

b. C# can interoperate with code written in other .Net languages.

Without much ado lets get on with C# programming. Here we go…

The First C# Program

All that you need to program in C# is Microsoft VisualStudio.Net Beta 2, .Net SDK Beta 2. (These you can either download from msdn.microsoft.com or you can get it along with your MSDN subscription.) You need to install it on a machine running under Windows 98, Windows 2000 or Windows XP.

namespace Simple

{

 

using System ;

class Class1

{

static void Main ( string[ ] args )

{

Console.WriteLine ( "Hello C#" ) ;

}

}

}

Before we understand how the program works, let us first see the steps involved in creating it.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

a. Start Microsoft Visual Studio.NET 7.0 from Start | Program | Microsoft Visual Studio.NET 7.0 menu option.

b. Create a new C# project from File | New | Project menu option. A New Project dialog as shown in the following figure would appear.

dialog as shown in the following figure would appear. c. From the New Project dialog box

c. From the New Project dialog box select project type as Visual C# Projects.

d. Select Console Application from the list of Templates.

e. Select a location (directory/folder) where this project should get saved. Give name to the project as Simple. Click on OK button.

f. A Class1.cs file would get created. This file would contain skeleton program. The VisualStudio.Net environment automatically creates this program. It contains a class called Class1 containing the function Main( ) .

g. Add the following line to the skeleton code.

Console.WriteLine ( "Hello C#" ) ;

h. To compile and execute the program use Ctrl + F5. On execution the message "Hello C#" would be displayed on the screen.

Now a few useful tips about the program…

a. C# is a pure object oriented language. It doesn't allow global variables or functions. All variables and functions should be defined inside a class.

b. All C# programs start from Main( ). Since Main( ) cannot be global it is enclosed in a class called Class1. void before the word Main specifies that Main( ) does not return anything. The static modifier used with Main( ) indicates that it can be called without creating an object of the class Class1.

c. string is a data type used to store strings. string[ ] represents an array of strings. Thus args is an array of strings. It stores the command line parameters, if specified by the user while executing the program.

d. To display anything on the screen we need to call the WriteLine( ) function. To this function we can pass strings, integers, floats, etc. Since the WriteLine( ) function belongs to the Console class we have to call it using Console.WriteLine( ). A function within the class can be accessed using the '.' Operator. Console class is used to perform input from keyboard and output to screen.

e. In C#, namespaces provide a way to group classes. Console class belongs to the System namespace. Hence to be able to use the Console class we need to import it from the System namespace. This has been done through the using System statement. The way the Console class has been enclosed within the System namespace, likewise

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

our class Class1 has been enclosed in the Simple namespace. The namespace concept is similar to packages in Java.

f. C# is a case-sensitive language. The naming convention used by .NET is that class names would start with a capital letter. If a single class name contains multiple words, each word's starting letter would be capital. The same applies to function names also. All keywords are in small case.

Let us now write another program that would show how to receive input from the keyboard. Here

it is…

namespace Simple

{

 

using System ;

class Class1

{

static void Main ( string[ ] args )

{

string s ; s = Console.ReadLine( ) ; Console.WriteLine ( s ) ;

}

}

}

To receive input from the keyboard we have used the ReadLine( ) function. This function returns

a string. This function is also a static member function of the Console class, hence we have called it using Console.ReadLine( ).

Note that C# does not have its own class library. It uses the class library provided by the .Net Framework. The .Net Framework provides the class library in the form of .Net Base Classes. Thus Console is a .Net base class. This class can be used by any other .Net-aware language.

Command-line Arguments

Instead of receiving input from keyboard we may want to supply input to it in the form of command-line arguments. Following program shows how to receive these arguments and print them out.

using System;

namespace cmdline

{

 

class Class1

{

static void Main ( string[ ] args )

{

foreach ( string str in args )

{

Console.WriteLine ( str ) ;

}

}

}

}

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

To supply command-line arguments we have to open the properties window of the project from the "Solution Explorer". A window will pop up. This window consists of properties that appear on the left pane of the window. We have to select "Configuration Properties" from it. As soon as we select this it expands into a tree with more underlying properties. Now we have to select the "Debugging" property. On doing this all fields related to the "Debugging" property appear on the right pane of the window. We then need to fill in the command-line arguments in the "Command Line Arguments" option. Press OK to finalize the option. In this program we have set command- line arguments as Nagpur Mumbai Bangalore. On executing the program it would output these arguments.

We can run this program from the Run dialog box that appears when we select 'Start | Run' option. To do so we must specify the command line arguments after the name of the EXE file.

FileHandling

.Net offers two classes for file operations-the File class and the FileInfo class. Both these classes are defined in System.IO namespace. The File class is derived from the Object class. It contains static methods and never gets instantiated. The FileInfo class is derived from FileSystemInfo class, which represents the file system. We can instantiate this class. The hierarchy of these classes is shown in the following figure:

hierarchy of these classes is shown in the following figure: Let us now understand the objective

Let us now understand the objective of creating two classes for file operations.

The static functions of the File class can be called to perform various file operations without creating an object. This avoids the overhead of instantiating objects. As against this, to call the member functions of the FileInfo class it is necessary to create an object. This is because FileInfo class contains non-static member functions. So if we wish to carry out a single operation on the file we can use the File class, avoiding the object creation overheads thereby. On the other hand if we wish to carry out multiple operations on the file (with the preservation of state of the object) we can use the FileInfo class. When we create a FileInfo object all the relevant information like size, attributes, authentication permissions are read in through the constructor. This information is then shared by other functions while carrying out multiple operations. If we use the File class for carrying our multiple operations then this information will have to be read in each time we perform a new operation.

Also, at times we are required to pass the file information to another application. In such a case it is necessary to create a FileInfo object and then pass its state to other application (this process is known as marshalling). Marshalling of object is possible only if the class in derived from the MarshalByRefObject class. Since the object of the File class cannot be created it has not been inherited from MarshalByRefObject class.

Reading And Writing To A Text File

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

In the following program we will perform reading and writing operations on a text file. We plan to write a few strings to a text file and read the strings back from it.

namespace fileoperation

{

 

using System ; using System.IO ;

class Class1

{

static void Main ( string[ ] args)

{

string str1 = "The .NET Revolution" ; string str2 = "Long live C# " ; string str3 = "Targeting the internet" ;

StreamWriter sw = new StreamWriter ( "C:\\file2.txt", false ) ; sw.WriteLine ( str1 ) ; sw.WriteLine ( str2 ) ; sw.WriteLine ( str3 ) ; sw.Close( ) ;

StreamReader sr = new StreamReader ( @"C:\file2.txt" ) ; // @ ensures that we don't have to use C:\\

string str ; do

{

str = sr.ReadLine( ) ; Console.WriteLine( str ) ; } while ( str != null ) ; sr.Close( ) ;

}

}

}

To understand this program we must first know what a Stream is. A stream is a sequence of bytes traveling from source to destination or traveling over a communication link. Two basic types of streams exist: Input stream and Output stream. An input stream is used for read operations while an output stream is used for write operations. The System.IO namespace contains functions to perform input and output operations.

Here we have created a new StreamWriter object and have passed 'false' to the constructor of the StreamWriter class along with the path. Here 'false' specifies that if the file exists, it should be overwritten. If we pass a true and if the file exists, it should be appended. In either case if the file does not exist, a new file is created. The WriteLine( ) member function of the StreamWriter class is overloaded to write out entities like object, boolean, int, etc. to a file.

Next, we have used a StreamReader class to perform the reading operation. Its ReadLine( ) function reads a line of characters from the current stream and returns the data as a string. This process is repeated till the end of file is reached. The hierarchy of stream I/O classes is shown in the following figure:

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com We have taken the first few toddling steps in C#. Imbibe the

We have taken the first few toddling steps in C#. Imbibe the matter presented here. We would take a peek below the hood of C# and explore its internal working next time.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: .C# - WinForms, Win App development made simple

For building Windows applications the .NET Framework provides two things-classes for managing the user-interface controls and an Integrated Development Environment (IDE) to design the Windows applications visually. Any window displayed in an application is created as a form. WinForms is a programming model used for building Windows applications through a form designer.

Using the form designer we can create standard windows, borderless windows, MDIs, dialog boxes, etc. We can add controls, set properties, create event handlers, and add programming logic to our form. A separate class governs each control that is added to a form. All the control classes are derived from the Control class. The classes are present in the System.Windows.Forms namespace. The classes remain same no matter which .NET language we use.

If you have used the Resource Editor of VB or VC++ you will have to spend little time to get familiar with the way the IDE works. You simply have to drag controls from a toolbox and drop them onto a form. Once inserted you can set the properties of the form as well as the controls using the IDE. The IDE generates only source code and not resource files as in VC++. The basic program to create a form looks like this:

using System; using System.Window.Forms

public class myform : Form

{

public myform ( )

{

}

static void Main ( )

{

myform a = new myform( ) ; Application.Run ( a ) ;

}

}

In Main( ) the Run( ) method of the Application class is called. To this method we have passed an instance of the form. The Application class provides static methods and properties to manage an application, such as methods to start and stop an application, to process Windows messages, and properties to get information about an application. The Run( ) method starts a standard application message loop on the current thread. If we execute this program it would merely show a blank form. Let us now see how to attach a menu to this blank form. Carry out the following steps:

a. Drag in the 'MainMenu' control from the toolbox and release it on the blank form.

b. Click on the control and type the menu item name as 'File'.

c. Add the items 'New', 'Open', 'Save', 'Generate' and 'Exit' to the 'File' menu in a similar manner.

The resultant form is shown in the following figure.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com Each menu item is governed by a control variable of the type

Each menu item is governed by a control variable of the type MenuItem. We can change the names of these variables through the 'Properties' window. For the program that follows we have used the names as filemenu that will hold the other menu items, newmenu, openmenu, savemenu, generatemenu and exitmenu.

Let us now decide what should happen when these menu items are selected. When we select the 'Generate' menu item, shapes like rectangle, ellipse and line should get generated at random and in random colors. On selecting the 'Save' menu item these shapes should be saved in a file. We must be able to load this file and display the shapes again. This would be achieved through the 'Open' menu item. When we click the 'New' menu item the earlier shapes should vanish and we must get a new form to draw new shapes.

While saving the shapes we should not save the image of the shape. Instead we should save the relevant information of the shape using which we should be able to regenerate the shape again when the file is loaded. This means we must write the object onto the disk while saving it and load it back while opening the file. This process of writing the state of an object is called serialization and reading it back is called deserialization.

To make all these activities to happen we need to add handlers for these menu items. The Windows Forms programming model is event based. When we click on a menu item it raises an event. In order to handle an event, our application should register an event-handling method. For adding these handlers click on the menu item for which we wish to add the handler. Then go to the 'Properties' window and select the 'Events' tab (shown by a yellow lightening icon). From the list of events select 'Click'. As a result an event handler called say, openmenu_Click( ) would get added to our code. On similar lines rest of the handlers can be added. All these handlers will get added to the Form1 class, which is the default class name.

Before we add code to these menu handlers let us insert four new classes. The first amongst these is an abstract class called shapes. In this class we will store the color of the shape in variables r, g, b, representing red, green and blue components of the color. The other three classes that we would add are line, rectangle and ellipse. These classes are derived from the shapes class. In these classes we will store the coordinates of the shapes. Each of these three classes would have a constructor to initialize the data members. Each class would have a function draw( ) which would contain the logic to draw the respective shape. This function would be declared as abstract in the base class shapes. To make all the classes capable of carrying

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

out serialization/desrialization we need to add the attribute Serializable as shown in the program listing given below.

using System ; using System.Drawing ; using System.Collections ; using System.ComponentModel ; using System.Windows.Forms ; using System.Data ; using System.IO ; using System.Threading ; using System.Runtime.Serialization ; using System.Runtime.Serialization.Formatters.Binary;

namespace myapp

{

[Serializable]

abstract class shapes

{

protected int r, g, b ;

Random rd = new Random( ) ; public shapes( )

{

 

r

= rd.Next ( 255 ) ;

g

= rd.Next ( 255 ) ;

b

= rd.Next ( 255 ) ;

//

put the thread to sleep for next 5

//

milliseconds to ensure proper color

//

generation

Thread.Sleep ( 5 ) ;

}

public abstract void draw ( Graphics g ) ;

}

[Serializable]

class line : shapes

{

int x1, y1 ; int x2, y2 ;

public line ( int i, int j, int k, int l )

{

x1 = i ; y1 = j ; x2 = k ; y2 = l ;

}

public override void draw ( Graphics gg )

{

Color c = Color.FromArgb ( r, g, b ) ; Pen p = new Pen ( c, 4 ) ; gg.DrawLine ( p, x1, y1, x2, y2 ) ;

}

}

[Serializable]

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

class rectangle : shapes

{

int x1, y1 ; int width, height ;

public rectangle ( int x, int y, int h, int w )

{

x1 = x ; y1 = y ; height = h ; width = w ;

}

public override void draw ( Graphics gg )

{

Color c = Color.FromArgb ( r, g, b ) ; Pen p = new Pen ( c, 4 ) ; gg.DrawRectangle ( p, x1, y1, width, height ) ;

}

}

[Serializable]

class ellipse : shapes

{

 

int x1, y1 ; int width, height ;

public ellipse ( int x, int y, int h, int w )

{

x1 = x ; y1 = y ; height = h ; width = w ;

}

public override void draw ( Graphics gg )

{

Color c = Color.FromArgb ( r, g, b ) ; Pen p = new Pen ( c, 4 ) ; gg.DrawEllipse ( p, x1, y1, width, height ) ;

}

}

public class Form1 : System.Windows.Forms.Form

{

private System.Windows.Forms.MainMenu mainMenu1 ; private System.Windows.Forms.MenuItem filemenu ; private System.Windows.Forms.MenuItem newmenu ; private System.Windows.Forms.MenuItem openmenu ; private System.Windows.Forms.MenuItem savemenu ; private System.Windows.Forms.MenuItem generatemenu ; private System.Windows.Forms.MenuItem exitmenu ; private System.ComponentModel.Container

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

components = null ; ArrayList s = new ArrayList( ) ; BinaryFormatter b = new BinaryFormatter ( ) ;

public Form1( )

{

InitializeComponent( ) ;

}

protected override void Dispose ( bool disposing )

{

if( disposing )

{

 

if ( components != null )

{

components.Dispose( ) ;

}

}

base.Dispose( disposing ) ;

}

[STAThread]

static void Main( )

{

Application.Run ( new Form1 ( ) ) ;

}

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

{

 

OpenFileDialog od = new OpenFileDialog( ) ; od.Filter = "dat files ( *.dat )|*.dat" ;

if ( od.ShowDialog( ) == DialogResult.OK )

{

FileInfo f=new FileInfo ( od.FileName); Stream st = f.Open ( FileMode.Open );

while ( st.Position != st.Length ) s.Add ( b.Deserialize ( st ) ) ; st.Close ( ) ;

}

Invalidate( ) ;

}

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

{

SaveFileDialog sd = new SaveFileDialog( ); sd.Filter = "dat files ( *.dat ) | *.dat" ;

if ( sd.ShowDialog( ) == DialogResult.OK )

{

FileInfo f = new FileInfo(sd.FileName); Stream st = f.Open ( FileMode.Create, FileAccess.ReadWrite ) ; foreach ( shapes ss in s ) b.Serialize ( st, ss ) ;

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

st.Close ( ) ;

}

}

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

{

 

Size sz = ClientSize ; Random rd = new Random( ) ;

for ( int i = 0 ; i < 10 ; i++ )

{

int shapeno = rd.Next ( 3 ) ; int x1 = rd.Next ( sz.Width ) ; int y1 = rd.Next ( sz.Height ) ; int x2 = rd.Next ( sz.Height - y1 ) ; int y2 = rd.Next ( sz.Width - x1 ) ;

switch ( shapeno )

{

 

case 0:

s.Add ( new line ( x1, y1, x2, y2 ) ) ; break ; case 1:

s.Add ( new rectangle ( x1, y1, x2, y2 ) ) ; break ; case 2:

s.Add ( new ellipse ( x1, y1, x2, y2 ) ) ; break ;

 

}

}

Invalidate( ) ;

}

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

{

Dispose( ) ;

}

private void Form1_Paint ( object sender, System.Windows.Forms.PaintEventArgs e )

{

Graphics g = e.Graphics ; foreach ( shapes ss in s ) ss.draw ( g ) ;

}

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

{

s.Clear( ) ; Invalidate( ) ;

}

}

}

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

When we click the 'Generate' menu item its handler gets called. In this handler an object of the Random class is created. The Next( ) method of this class generates a positive random number less than the specified number passed to it.

We have used this function to not only decide which shape should be generated but also the coordinates of this shape. Using these coordinates we have created an object of rectangle, ellipse or line class. While creating these objects the constructors of the respective classed get called. Since all these classes are derived from the shapes class, firstly the base class constructor gets called. This constructor selects a random color.

The references of objects of line, rectangle and ellipse are stored using a collection class called ArrayList. The object s of this class now consists of references of objects of the line, rectangle and ellipse classes. As these classes are derived from shapes, it is perfectly legitimate for a reference to shapes to be set up to point to either shapes or one of its derived classes.

Next we have called the Invalidate( ) method which results in the Form1_Paint( ) method getting called. Here we have collected back each reference from the array s into a reference ss of type shapes. Using this reference it has then called the draw( ) method. Depending upon which (line, rectangle or ellipse) reference is present in ss the draw( ) function of that class gets called. The resulting form is shown below.

that class gets called. The resulting form is shown below. If we wish to save the

If we wish to save the file we can click on 'Save' menu item. When we do so savemenu_Click( ) gets called. We have created an object of the SaveFileDialog class and used a "*.dat" filter for it. When we type in a file name and click Ok, a FileInfo object gets created with the selected name. The Open( ) function returns a Stream object associated with the file. We have collected it in a Stream reference. We have used the BinaryFormatter object to serialize the objects. The BinaryFormatter serializes and deserializes an object, in binary format. We have added a BinaryFormatter object b to our class. The Serialize( ) method of this class serializes the object to the given stream. After serializing all the elements of the array we have closed the stream using the Close( ) method.

When we click 'Open' menu item an OpenFileDialog is popped with the appropriate filter. Here also we have created a FileInfo object and collected the corresponding Stream of the specified file. Next we have used a while loop to deserialize the objects until the end of stream is reached. The Deserialize( ) method deserializes the specified stream into an object. We have collected

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

these objects into our array, closed the stream and called Invalidate( ) function for painting these shapes.

When we click 'New' menu item the array is cleared by deleting all the elements in the array. After this we have called Invalidate( ). This time the method Form1_Paint( ) draws nothing as the array is empty, thereby resulting a clean form.

On clicking the 'Exit' menu item the Dispose( ) method gets called and the form is disposed.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

The earliest form of reuse was in the form of Static Libraries. These libraries contained object code of functions. During linking the object code of the library functions (usually stored in .Lib file(s)) was linked with the object code of the program calling those functions to form an executable file. The linking phase used to precede execution. This way the library functions could be reused by different applications calling them. This however led to wastage of storage space as the object code from the function library used to get replicated into every application using it. This is shown in Figure 1.

into every application using it. This is shown in Figure 1. Figure 1 In multitasking environments

Figure 1

In multitasking environments if two applications are running in memory each calling the same library function then two copies of the same function would be running in two different processes. This led to wastage of precious memory space. Also if a bug was found in the library functions the library as well as the client program using it had to be re-compiled and re-distributed. A recipe for disaster for sure!

To avoid the wastage of memory and disk space Microsoft suggested the concept of Dynamically Linked Libraries (DLLs). Functions from these libraries never became part of an application trying to call them. Instead they used to get linked with the applications calling them at run-time. Moreover, multiple applications calling them used to share the same copy of the library function present in memory. A developer could simply place the DLL in Windows directory, Windows\System directory or in the same directory as the EXE file using that DLL and then rely on the operating system to do the linking at run-time.

This to begin with was a welcome change from the static libraries of the past. However, as programmer's started building DLLs they realized that the concept though apparently promising is infested with several problems listed below:

Name mangling - To permit function overloading C++ compilers mangle (decorate) the name of each function called/defined in the program. Since the C++ language doesn't lay down any rules about how name mangling should be done, each compiler writer adopted his own strategy to

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

create mangled names. As a result, if one is to load the DLL explicitly as shown in the following code it was difficult to mention the mangled name.

HMODULE h = :: LoadLibrary ( "myfunctions.dll" ) ; fptr = getProcAddress ( h, "mangled function name" ) ; // call the function using the function pointer fptr

Thus the DLL created using one C++ compiler was not of much use to another C++ program that

is compiled through another compiler. As a remedy to this it was suggested that we should use

ordinal numbers in place of function names. Easier said than done! Ask yourself ids of how many of your co-employees you remember and you would get the answer why this scheme was not practical.

Cross-Language Usage - Instead of storing exported functions we can create a DLL that would hold a C++ class. But this class is of little use to a C programmer (as C doesn't understand a class) or to a Java programmer (as Java doesn't understand the C++ syntax). Thus a cross- language usage was a no-no in DLLs.

DLL Hell - Imagine a DLL containing some classes. Over a period of time we might be required to

change the signature of the methods present in classes for implementing additional functionality.

If we create this DLL and overwrite the existing DLL with the new one then the clients using the

older version of the DLL would break. To avoid this we need to maintain both the DLLs leading to versioning problems.

Location Transparency - DLLs did not offer location transparency, as the clients using the DLL were not independent of the path where the DLL was stored.

Component Object Model

Component software is a paradigm for designing and implementing an application by putting together independent pieces of software instead of writing one big monolithic application.

COM components have unique characteristics that make them very attractive as building blocks for larger applications. They can be distributed either as DLLs or as EXEs. Clients can bind to the components at run-time and don't have to be recompiled due to any upgrades to the components. The components can be transparently relocated on a remote computer without affecting the clients i.e. local and remote components are treated in the same manner. This makes distributed computing very easy. The components can be written in any programming language as long as they follow a standard memory layout prescribed by the COM specifications. Additionally COM is object-oriented. COM components along-with COM interfaces support the concept of encapsulation and polymorphism.

These smaller units with well-defined behavior can be reused across any language. Thus a COM component written in VisualBasic could be reused by a Visual C++ client and vice versa. COM imposed a binary standard. Under this standard, components communicated with each other via interfaces. COM identified components via Globally Unique identifiers (CLSIDs or GUIDs).

Components were registered in the system registry. The benefit of registering was that it was very easy to see what components were available on one machine. With COM it became easy to write

a component in any of the languages supporting COM and to call it from other languages. But this ease was topped up with complexity. COM was difficult to learn. Moreover storing information about all components in the registry made the process of installing software quite complex.

Side-By-Side

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Windows 2000 introduced a feature called side-by-side that lets us install DLLs in the application's directory. We can install two versions of the same DLL in a system. Applications are then free to use the specific version for which they were designed and tested. This way different applications can use different versions on the same system. This arrangement allows developers to build and deploy more reliable applications because developers are able to specify the version they will use for their application, independent of other applications on the system. However, the down side of this arrangement is that un-installation of these versions becomes complicated.

Assemblies

If an application is to use a COM component it needs the methods and properties stored in COM component, the type library information and the registry entry of the component. If for any reason any of these is unavailable the component is rendered unusable. Let us now see how .Net overcomes this problem using Assemblies.

Assemblies is the .NET's approach to code reuse. It has taken some concepts from its predecessors, namely, DLLs and COM/COM+. Any .Net code on compilation is stored in an Assembly. In addition to the IL code an assembly also contains metadata that describes the assembly as well as any resources that are used by the IL code.

as well as any resources that are used by the IL code. Figure 2 The metadata

Figure 2

The metadata include the types (classes, methods and properties) exported from the assembly and a manifest. A manifest is a data structure. It serves the same purpose as the type library and associated registry entries do for a COM component. Manifest contains more information than a type library. The details of the manifest structure would be discussed in the next article.

Assemblies can be loaded using the side-by-side technique. This means a different version of the same assembly can be used inside a single process.

Assemblies support Zero-impact installations. Installations can be as easy as copying the files that belong to an assembly.

An assembly may represent one file or might be spread across several files.

Shared and Private Assemblies

There are two types of assemblies available: private assemblies and shared assemblies. A private assembly is used by only one application while a shared assembly is shared amongst different applications.

By default when we compile a C# program, the assembly produced will be a private assembly. This assembly (DLL/EXE) should be placed in the same folder as the calling application. With a private assembly it's not necessary to think about naming conflicts with other classes or versioning problems because each application has its own copy of the assembly.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

In shared assemblies we must be careful that the assembly must be unique, and therefore, have a unique name (called strong name).

Building Private Assemblies

Now we will see how to build a private assembly. We plan to write a class library consisting of a function called display( ). We will call this function in a client program, which we will create later. To build a library start VisualStudio.NET and create a Visual C# project with template type as 'Class Library'. Name the project as fontassembly. By default the assembly created for this project would be private.

Add the following code to the Class1.cs file.

using System ; using System.Drawing ; using System.Windows.Forms ;

namespace fontassembly

{

 

public class mytext

{

public void display ( Form fr, String s, Color c, String fname, int size, Point pt )

{

Graphics g = fr.CreateGraphics( ); Font myfont = new Font ( fname, size ) ; SolidBrush mybrush = new SolidBrush (c); g.DrawString ( s, myfont, mybrush, pt ) ;

}

}

}

The display( ) function simply draws text with the specified Font and Brush. On building the project a fontassembly.dll file would get created in the fontassembly\bin\Debug subfolder.

Building the client

Let us now build a client that would use the private assembly that we have created. We plan to make a from-based client. To create the client select a 'Windows Application' project.

When we click on the form some text should be displayed at the position where we click. This can be achieved by calling the display( ) function from fontassembly.dll in the myform_MouseDown( ) handler. The client code is shown below:

using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using fontassembly ; // to be added

namespace fontclient

{

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

public class myform :

System.Windows.Forms.Form

{

 

private System.ComponentModel.Container components = null; mytext t = new mytext( ) ; public myform( )

{

InitializeComponent( ) ;

}

protected override void Dispose( bool disposing )

{

if( disposing )

{

 

if (components != null)

{

components.Dispose( ) ;

}

 

}

base.Dispose( disposing );

}

[STAThread]

static void Main( )

{

Application.Run(new myform( ) ) ;

}

private void myform_MouseDown ( object sender, System.Windows.Forms.MouseEventArgs e )

{

if ( e.Button == MouseButtons.Left )

{

 

Point pt = new Point ( e.X, e.Y ) ; t.display ( this, "Hello", Color.Red, "Comic Sans MS", 30, pt ) ;

 

}

}

}

}

Note that the mouse event handler should be added separately. For this go to the 'Properties' window and select the 'Events' tab (shown by a yellow lightening icon). From the list of events select 'MouseDown'. An event handler called myform_MouseDown( ) would get added to our code.

In the myform_MouseDown( ) event handler we have first checked whether the left mouse button has been clicked. If so then we have called the display( ) method of the mytext class from the fontassembly assembly.

We have created a mytext object in our form class. For the mytext class to become available we have added the statement using fontassembly. However this is not enough. We also need to add a reference to the library. To do this we should right click on 'References' in the Solution Explorer window and select 'Add References'. On doing so the following window appears.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com Since our assembly is a private assembly (and not a shared one)

Since our assembly is a private assembly (and not a shared one) it would not be listed in this window. So click on 'Browse' and select the fontassembly.dll from the fontassembly\bin\Debug directory. As a result the DLL would get copied into the fontclient\bin\Debug subfolder of the client. Now we can refer to this class in the client code.

On executing the client you would get the window shown below. Click on the form anywhere using the left mouse button and a string "Hello" would appear there.

button and a string "Hello" would appear there. With the first assembly under your belt, you

With the first assembly under your belt, you are ready to get into the more complicated stuff like shared assemblies, versioning, application domains, etc. But that would have to wait till the next article.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: The .Net Revolution

If you take a peep into the future you would see .Net written all over

paradigm that will change the way you think about writing software. This chapter would help you to understand the .Net vision.

it.

.Net offers a whole new

Though it might be difficult to imagine today the world was still in the mainframe era two decades ago. Few people had access to or used computers. Home computing was unheard of and computers were used only through an IT department at work. The three most influential factors that were responsible for changing this scenario are the PC, the Graphical User Interface and the World Wide Web. With their arrival millions of more users started using computers. The ability of handling graphics, audio and video with ease was sufficiently exciting for an average user to get drawn towards computing. They were responsible for democratizing computing for hundreds of millions of people and for transforming computer into a mass-market product. Computing has now become a key activity in the daily lives of business employees and home users.

What will the next generation of computing look like? It would be an online world where millions of PCs, servers, PDAs (Personal Data Assistants), email devices, mobile phones, digital diaries, digital copiers, etc, would collaborate with each other through internet based services. It would make available the information that you and your business needs irrespective of the place where you are and the computing device, platform or the application that you are using. This vision however is yet to be achieved. Let us now see what are the major hurdles that current computing world needs to cross to achieve this vision.

Server-Centric Model

Today's Internet is still the reflection of mainframe era's server-centric model. Most of the information your business needs is locked up in centralized databases and served to you a page at a time. The browser largely plays the role of the dumb terminal. Web pages provide a "picture" of data, not the data itself. Integrating this data with your business's existing systems and that of your partners is not only costly but often frustrating.

Poor Integration

Though today's standalone applications and web sites provide good functionality and data most of the time they still work in isolation. One has to navigate manually between websites, devices and applications, rarely being able to integrate the functionality and data. An apparently simple task of arranging a meeting with colleagues and automatically updating every attendee's calendar still remains a complicated computing job. As a result, productivity suffers.

Device-Centric View

As the software engineering matured the demand on productivity, scalability and robustness increased. This led to developing software in the form of reusable components. With the widespread availability of network the concept of componentization was extended to Distributed Computing. The DCOM (Distributed Component Object Model) from Microsoft, CORBA (Common Object Request Broker Architecture) from Object Management Group and the RMI (Remote Method Invocation) from Sun became popular models for developing software in the form of components that would work in the distributed environment. To help build these reusable components two frameworks came into existence-the DNA (Distributed Network Architecture) framework and the J2EE (Java Enterprise Edition) from the Java camp. However, both these frameworks were built around the platform that is connected to the Internet. This promotes a device-centric view of the world.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Web-Centric View

What is needed today is to change the framework from device centric to Internet/Intranet/Web- centric. Under this framework software will be available as a set of distributed services with the devices (PC, PDA, Mobile, etc.) acting as mere points of delivery of services. These services are known as Web Services. Like components they are programmable and reusable. They are available anywhere via the Internet. Programs built using this model will run across multiple websites extracting information from each of them and combining and delivering it in a customized form to any device anywhere in the world.

The potential of Web Services is unlimited. For example, a software company may provide a Web Service to calculate income tax. Any company that wants to calculate income tax can subscribe to this Web Service. The customer company need not deploy the income tax calculator. It simply needs to access the Web Service. The company offering the service can dynamically update it to accommodate new taxation rates. The subscribers won't have to do anything to get the new updates. In future a collection of such Web Services may replace packaged software. Other Web Services that can be developed include weather information; stock quotes, shipping status, news items, etc. I think you get the picture now.

How will businesses and their customers benefit from Web services? As Web services break down the distinctions between the Internet, standalone applications and computing devices of every kind, they enable businesses to collaborate to offer and unprecedented range of integrated and customized solutions--solutions that enable their customers to act on information any time, any place and on any device. The following figure captures the essence of the .Net vision.

To meet the challenge of next generation of internet-based computing Microsoft has come up with the .Net platform. This platform simplifies the process of building these solutions and provides a

framework for integration and interoperability. This platform is based on open standards like (XML and SOAP) so that it can work across all programming languages and operating systems. It helps you to combine the power of PCs and smart devices with the richness of Internet. To make Web services a reality Microsoft has addressed the problem at three levels. It has provided a framework to help build the web services, development tools and languages to make this development easy and a server infrastructure to deploy and operate the web services. Let us take

a brief look at each of these.

Development Tools and Technologies

A productive set of tools is critical to carry out successful development on a new platform like

.Net. Visual Studio.net provides a complete solution for building, deploying, and running Web services. It helps you to maximize the performance, realiability, and security of your Web services.

Visual Studio.Net helps developers quickly build Web services and applications that scale easily, using the language of their choice. This multi-language development tool has been built especially for .Net. You can use programming languages like Visual Basic, C++ and the new language C# for your development work under .Net. Visual Basic was not object oriented, hence

it has been spruced up and christened into VB.Net. Visual C++ has been extended to build Web

services. You can continue to use it build traditional desktop Windows application s too. A brand new language called C# (pronounced as C sharp) has also been introduced. This language combines RAD (Rapid Application Development) feature of Visual Basic, OO of Visual C++ and

portability and platform independence of Java. In addition to these languages provided by Microsoft, there will be over 20 languages provided by partners, including Perl, Python, COBOL, and Eiffel from which developers can choose. For server side programming instead of using non- OO scripting languages like VB SCript we can use C#, VB.Net or C++. Access to databases has also been improved by providing ADO.Net.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Framework

The .Net framework is a high productivity, standards-based, multi-language application execution environment that handles essential plumbing chores and eases deployment. It provides an application execution environment that manages memory, addresses versioning issues and improves the reliability, scalability, and security of your application. The .Net framework consists of several parts, including the Common Language Runtime and a rich set of class libraries.

Microsoft has also provided a set of core Web services that releases developers from the burden of building everything themselves. By integrating with these core services to perform routine tasks, developers can concentrate on building high-value, business-critical Web services. Microsoft Passport is the first such service which provides authentication services. Microsoft and many other companies plan to develop more core services for users and enterprises.

Server Infrastructure

Web services should be built on a infrastructure that offers developers the benefits of modular architecture, economical and linear scaling, security, reliability, manageability, and high availability. The .Net Enterprise Servers and the Windows 2000 Server family make up the Microsoft .Net server infrastructure for deploying, managing, and orchestrating Web services. Designed with mission-critical performance in mind, they provide enterprises with the agility they need to integrate their systems, applications, and partners through Web services, and the flexibility to adapt to changing business requirements.

The .NET Enterprises Servers are:

Application Center 2000 to deploy and manage highly available and scalable Web applications

BizTalk Server 2000 to build XML-based business process across applications and organizations

Commerce Server 2000 for quickly building scalable e-commerce solutions

Content Management Server 2001 to manage content for dynamic e-business Web sites

Exchange 2000 Server to enable messaging and collaboration

Host Integration Server 2000 for bridging data and application on legacy systems

Internet Security and Acceleration Server 2000 for secure, fast Internet connectivity

Mobile Information 2001 Server to enable application support by mobile devices like cell phones

SharePoint Portal Server 2001 to find, share and publish business Information

SQL Server 2000 to store, retrieve and analyze structured XML data.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: The .Net Framework

.Net is a platform that would help us to build service-oriented applications to meet the demands of today's Internet businesses. These applications typically gather information from, and interact with, a wide variety of sources regardless of the platforms or languages in use. Integration of services available through different sources and platforms calls for an open standard for describing data and a development platform to help developers create and deploy distributed applications (services). To this effect Microsoft has decided on XML (Extensible Markup Language) for describing the data and the .Net framework as the development platform. The .Net framework is very versatile and addresses many problems that the developers commonly face. This article would discuss these problems and the solutions offered by .Net.

discuss these problems and the solutions offered by .Net. OS Usage In the older days of

OS Usage

In the older days of DOS programming calling the ROM-BIOS or DOS routines was a messy affair. These functions did not have names hence to call these functions it was necessary to pick up these addresses from Interrupt Vector Table (IVT). Moreover to communicate with these functions it was necessary to setup the CPU registers. And if you managed to master this you were required to content with the hardware dependencies. That is the process of a simple operation like drawing a line varied from one type of display adapter to another. To minimize these difficulties several libraries came into existence. They were useful but were language dependent. With Windows things improved to the extent that the Application Programming Interface (API) functions could be called like any other library function. Moreover with the introduction of device independence the programmer was not bothered to worry about the device on which the programmer would finally run. It was Windows Graphical Device Interface (GDI) that adjusted the drawing according to the capability of the device. Also, the same API functions could be called easily through different languages. However the Windows API functions typically needed several parameters to be passed during the call as shown in figure 2.1. Also, API being merely a library of functions could not support the object-oriented programming paradigm. To

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

bring the benefits of object-oriented programming to Windows programming Microsoft created the Microsoft Foundation Class (MFC) library. Likewise, Borland came up with Object Windows Library (OWL). However thought these libraries were very powerful they were not usable across languages. Thus, a good MFC class meant nothing for a Visual Basic programmer. Similarly, a Visual Basic library function meant hardly anything for a VC++ programmer.

The .Net framework attempts to resolve these difficulties by providing a Common Language Runtime (CLR) and a set of base classes that can be accessed through any .Net compliant language.

that can be accessed through any .Net compliant language. Little Reuse In procedural languages like C

Little Reuse

In procedural languages like C reuse was limited to calling the same library functions from different programs. These functions however were not extensible. They were required to be use on a "as is, where is" basis. Also structured programming languages did not model the real world very well. For example, if a C program is used to create a window then there were no language elements that could be identified with the window or its elements like toolbar, menu, status bar, etc. In the procedural programming paradigm the whole emphasis was on dividing a job into several smaller jobs and then implementing these jobs through the individual functions. Importance was given to the operations rather the data on which these operations are performed. While dealing with complex systems this was found to be an unrealistic programming model. World is object-oriented and programmer being the part of the world should also deal with a system that he is trying to program in the form of objects and their inter-relationship. Object- oriented languages embrace these concepts and hence have become immensely popular amongst programmers. C++ and Java are good examples of these. These languages promoted reuse by letting you inherit features of one class into another and then providing additional features in the new class. This was possible even if the source code of the first class was not available. This reuse was a big step forward. However the reuse was restricted within the language. Thus, a Java class was not of much use to a C++ programmer and vice-versa. To promote language independent reuse Microsoft came up with a bold new technology called Component Object Model (COM). COM was a binary specification and components built as per this specification could be used by not only the conventional languages like C or C++ but also by scripting languages like VBScript and JavaScript. To accommodate these wide range of languages a lot of plumbing code was required to be built. Also, COM didn't support cross- language inheritance or cross-language debugging. Instead of adopting a philosophy of letting all kinds of languages to use COM components and requiring a lot of plumbing code to be written in

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

the process .Net adopts a different philosophy.

In .Net the capabilities of languages itself is raised in such a manner that they can use COM components without being required to write lot of plumbing code.

without being required to write lot of plumbing code. Messy Runtime DOS was a single tasking

Messy Runtime

DOS was a single tasking operating system, which could run only one program at a time in memory. With the dramatic increase in the computing power it was unrealistic to expect that a user will like to use the entire power to run only one program. Windows could utilize this computing power by letting users run several programs at a time by creating a powerful runtime. However this runtime had the following problems:

Poor error handling - Windows returned error codes which is not the object oriented way of handling errors. It has now become a common norm that errors should be handled through exceptions and nit through error codes.

Costly Inter Procedure Calls (IPC) - When multiple processes are running in memory Windows runtime ensures that no process barges into the memory of the other. However there is often a need to communicate between processes. This calls for marshalling (conversion of parameters being passed to a function into a byte stream) and unmarshalling (conversion of byte stream into data types). There is a severe overhead in this as lot of copying of parameters takes place. If this is to be avoided then the second process can be made as a DLL and then made to run in the same address space as the first. This has a disadvantage that if the DLL fires the process in whose address space it is running also fires.

.Net overcomes this limitation by using a concept called Application Domains.

also fires. .Net overcomes this limitation by using a concept called Application Domains. Compiled by rmshankar@yahoo.com

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Changing World

In the last decade or so computing has moved from the confines of an organization to a model where computing takes place in a distributed environment spread across multiple branches/offices present at different geographical locations. Also, integration becomes a major issue when your computing model has to work in tandem with that of your partners, customers and suppliers. This involves complexities like different computers, different operating systems, different languages used for development, etc. Let's elaborate on this. Suppose we wish to develop an Internet application that allows businesses to communicate vital information with each other across existing communication lines. Let's look at typical solution that can be offered to this problem using Microsoft technologies. If the application is an n-tier application then we would need HTML, DHTML & Java Script in the front-tier; VBScript, ASP, MTS, C++, VB, COM in the middle-tier and SQL, ADO in the back-tier. Developers possessing

sufficient skill in all of these areas are few and costly. In short, a perfect recipe for development nightmare. Even if the developers are able to successfully develop the applications, they would be required to spend hours battling component version conflicts (popularly known as DLL Hell) when the time comes to install their products. Assured distribution nightmare, in short. Sun's solution to this problem could be to use Java applets and servlets in the front-tier, Enterprises Java Bean (EJB) or CORBA or RMI in the middle-tier, and JDBC and a suitable database in the back-tier. The common theme here is every developer should learn Java language. This is a far-fetched dream. Though an attempt to make every programmer a Java programmer has met with more than a lukewarm success, the ground reality is that there would

be several languages in existence, each camp having its own faithful band of

has understood this reality and hence lets you use language for your taste for carrying out the development.

programmers.

.Net

taste for carrying out the development. programmers. .Net Deployment Nightmare DLLs are created with a motive

Deployment Nightmare

DLLs are created with a motive to share them between different applications. Hence while installing them instead of placing them in any particular application's directory they are installed either in Windows directory or in Windows\System directory. Thus whichever application wants to use a DLL file it can load it from one of these directories. This, on the face appears to be pretty straightforward. But when a new version of the DLL is released it should not be copied on top of the earlier version. Otherwise the clients that were using the earlier DLL might break. Thus the DLLs have to have different names if the two versions are to coexist. These versioning problems are popularly known as DLL hell.

Documents downloaded from www.funducode.com

COM has overcome this versioning problem by storing two different versions of the component in two different directories and then registering these components in the Windows registry using two unique IDs (popularly known as globally unique id or GUID). However, the installation of a COM component was a little unrealistic because the COM component used to get stored in one directory, its CLSID used to be in registry and its interface (through which the functions of the COM component can be accessed) used to be in the type library of the component. If any of these used to go bad the component used to be rendered useless.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: Thinking in C#

C# (pronounced as 'C Sharp') is a new object-oriented language designed at Microsoft by Anders Hejlsberg. This language would help programmers create secure, robust, portable, distributed object-oriented applications for the internet. But that is hardly a definition that would impress a programmer. What he would be most interested in knowing is how this language is going to make a difference to his daily work and how is it different than existing popular languages like C++, Visual Basic and Java. The answer is simple-it combines the power of C++ with productivity of Visual Basic and elegance of Java. That's a tall promise. We need to examine this claim with a thick lens.

Power of C++ - C# brings with it object-oriented paradigm of C++. It implements the same through encapsulation, inheritance and polymorphism.

Productivity of Visual Basic - Promotes Rapid Application Development through simpler GUI programming with easy drag & drop support. Properties & Events are part of the language itself.

Elegance of Java - No pointers (unless explicitly mentioned), fixed-size primary data types, Unicode characters, Type-safety, No multiple-inheritance, Garbage collection, Platform independence.

The C# language is disarmingly simple. C# is the first language that has been designed from ground up with Internet in mind. Using C# we can create a whole gamut of applications including Windows-based applications (WinForms), server-side applications (Dynamic Web Pages, Web Services), client-side applications (Web Forms & Web Controls), enterprise applications (ADO.NET), mobile applications, components (Assemblies), etc.

The First C# Program

Best way to learn a new language would be by writing programs and then comparing them feature by feature with popular existing languages like C++, Visual Basic and Java. So let us begin with the first program that displays a message "Hello C#". Here is the program…

namespace Simple

{

 

using System ;

class Class1

{

static void Main ( string[ ] args )

{

Console.WriteLine ( "Hello C#" ) ;

}

}

}

On execution, this program prints a message "Hello C#" on the screen. To create this program we would use the Visual Studio.NET environment in the steps mentioned below:

a. Start Microsoft Visual Studio.NET 7.0 from Start | Program | Microsoft Visual Studio.NET 7.0 menu option.

b. Create a new C# project from File | New | Project menu option. A New Project dialog as shown in the following figure would appear.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com c. From the New Project dialog box select project type as Visual

c. From the New Project dialog box select project type as Visual C# Projects.

d. Select Console Application from the list of Templates.

e. Select a location where this project should get saved. Give name to the project - Simple. Click on OK button.

f. A Class1.cs file would get created.

g. Type the program in Class1.cs file

h. To execute the program, programmers using Visual Studio.NET should use Ctrl + F5. Those who do not have Visual Studio.NET should go to DOS prompt and execute the command

C>csc Class1.cs.

Here csc stands for C Sharp Compiler. The output of this command would be an EXE file. To execute the .EXE file just type its name on the command prompt. (From now onwards we would build applications using Visual Studio.NET.)

Here we have used console application from several templates. As we go along we would use other templates also.

The program execution starts from the Main( ) function. Since C# is a pure object-oriented language it does not allow us to create global variables and functions. Instead, all variables and functions should be defined inside a class. Hence it is necessary to define the Main( ) function in some class, say Class1. Except for the line marked out in bold in the above program the rest of the code shown in the program is generated by the Wizard.

A class is a blue-print from which specific objects can be created. A class is similar to a data type and an object is similar to a variable. The way we can create several variables from an int type, likewise we can create several objects from a class like Class1. The class, like structure in C, allows us to create our own (user-defined) data types by combining intrinsic or other user-defined data types. Unlike structures in C a class can hold data as well as functions. Thus a class indicates what kind of data an object of its type can hold and what operations (like addition, subtraction, display, etc.) can be performed on this data. In short, the class specifies what data and what functions will be included in objects of that class. We would learn more about this in the Chapter "Classes and Objects".

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

The void keyword before Main( ) specifies that this function does not return any value. We would later discuss what static really means. But for now it is necessary and removing it would result in an error. The string is a data type used to hold a string. The string[ ] represents an array of strings. As you can see args, the argument of Main( ) has been declared to be of type string[ ]. It can be used to store command-line arguments, if supplied by the user.

To send output to the screen we have used the WriteLine( ) function. To this function we can

pass strings, integers, floats, etc. Since WriteLine( ) belongs to the Console class we have to

use the form Console.WriteLine( ) to call

related classes in one namespace. The Console class belongs to the System namespace. To be able to use the Console class in any program we need to import it from the namespace, which has been done in our program through the statement using System. Like the Console class our class is also enclosed in the Simple namespace. This namespace is generated by the Wizard from the project name that we had specified while creating the project.

it.

.NET organizes its classes by grouping several

Remember that C# is a case-sensitive language. The naming convention used by .NET is that class names should start with a capital letter. If a single class name contains multiple words, each word will have its starting letter in capital. The same applies to function names as well. All keywords are in small case. Printing Command-Line Arguments

We can stretch the first program done above to add the ability of printing the command-line arguments that may be supplied while executing the program. The enhance program is given below:

namespace Simple

{

 

using System ;

class Class1

{

static void Main ( string[ ] args )

{

for ( int i = 0 ; i < args.Length ; i++ ) Console.WriteLine ( args [ i ] ) ;

}

}

}

The for loop walks through the args[ ] array printing each command-line argument in the process. Command-line arguments can be supplied through the 'Start | Run' menu item by following the program name with the arguments that we intend to provide. To find out the number arguments supplied by the user we have accessed the Length property of the array. The Length property returns the number of elements in the array, which is then used to govern the conditional statement in the for loop.

Now that we have the capability to print messages on the screen let us now turn our attention to the basic building blocks of a language, namely, Data types.

Data Types

The data types in C# can be divided into different groups. Every data type has a strictly defined size and range. This size would remain same irrespective of the platform being used. These groups are shown in the following tables:

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Integers

Data

Type

Signed/Unsigned Size

sbyte

signed

1 byte

byte

unsigned

1 byte

short

signed

2 bytes

ushort unsigned

2 bytes

int

signed

4 bytes

uint

unsigned

4 bytes

long signed

8 bytes

ulong unsigned

8 bytes

Range

-128 to 127 0 to 255

-32768 to 32767 0 to 65536 -2147483648 to 2147483647 0 to 4294967295 -9223372036854775808 to

9223372036854775807

0 to 18446744073709551615

Any whole number value can be an integer value. The data types in this group cannot hold fractional values.

Floating Points

Data

Type

Signed/Unsigned Size

Range

float signed

4 bytes

1.5 x 10 -45 to 3.4 x 10 38

double signed

8 bytes

5.0 x 10 -324 to 1.7 x 10308

The data types in this group can hold Floating-point numbers representing decimal values with a fractional component.

Character

Data

Type

char

The data type in this group can hold a character with a 16-bit Unicode value. Unicode defines fully international character set that can represent all of the characters found in all human languages. It is the unification of dozens of character sets such as Latin, Greek, Arabic, Cyrillic, Hebrew, Katakana, Hangul and many more. For this purpose it requires 16 bits to represent each character.

Boolean

Data

Type

Bool

This type can hold logical values. It can have only one of the two possible values, true or false.

Decimal

Data

Type

decimal signed

bytes This data type is a dedicated type for financial calculations. It represents higher precision floating-point numbers. It allows us to specify currency amounts.

Signed/Unsigned Size

unsigned

Range

2 bytes

Signed/Unsigned Size

NA

1 byte

Range

true or false

Signed/Unsigned Size

Range

16 1.0 x 10 -28 to 7.9 x 10 28

C# imposes some rules while using these data types. These rules are explained below with the help of code snippets:

Rule 1: Before using any variable it must be initialized with a value.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

int i ; Console.WriteLine ( i ) ;

This would result in an error since before printing the value of i it has not been initialized. Unlike C/C++ there is no concept of garbage values.

Rule 2: The variable can be initialized with a value that is within the range of its type.

short s = 40000 ;

This would result in an error. Here, since s is of 2 bytes it can store a maximum value of 32767. Unlike C and C++ the value would not get wrapped to the other side of the range.

Rule 3: While initializing the destination type must be larger that the source type.

short s = 40 ; byte b ;

b = s ;

Here, the value of a short variable is being assigned to the variable of type byte. Since, size of a short is larger than that of a byte this results in narrowing of the value. Narrowing conversions are not supported implicitly by C#. To make this work we need to do an explicit conversion like,

b = ( byte ) s ;

C# supports implicit wider conversion. Hence the statement s = b would work.

Rule 4: sbyte and short are converted to an int type, whereas, byte and ushort are converted to a uint type while performing arithmetic operations on them.

short s1 = 40, s2 ; byte b = 6 ; s2 = s1 + b ;

Here, s1 and b would be converted to an integer type before performing addition. The resultant value would be an integer. Assigning an integer value to a short variable would result in an error. To make this work we have to write s2 = ( short ) ( s1 + b ).

Character type can be converted into integers and manipulated with the integer operators such as the addition and subtraction operators. For example,

char c = 'a' ; int i ;

i = c ;

i = c + 1 ;

Rule 5: Boolean type is incompatible with rest of the data types.

int i = 40 ;

bool b = true ;

i

= b ;

b

= ( int ) i ;

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

The bool type is returned by all relational operations such as a < b. The bool is also a type required by the conditional expressions that govern the control statements such as if, while and for. It solves the problem where programmers mistakenly use = instead of == resulting in unexpected behaviour. This distorted type safety. For example, several years ago, a space bound rocket crashed just minutes after launch costing NASA millions of dollars. Upon investigation, it

was discovered that the crash was a result of a software failure. Specifically the fault was traced

to a buggy line of C code in which the programmer had mistakenly used = at a place where ==

was needed. Let us see with an example how C# solves this problem.

int a = 10, b = 50 ; if ( a = b ) a = 70 ;

This code would result in an error because the result of the assignment statement a = b is not a bool value.

Control Statements

Statements like for, return, goto, break, and continue work in the same way in C# as they do in

C and C++. But there are differences in the way if, while, do

Moreover an additional looping instruction called foreach has also been added in C#. Let us now understand the improvements that have been made to the control instructions.

and switch statements work.

while

switch Statement

Unlike C and C++, control in a switch statement in C# is not permitted to "fall through" to the next case if a case gets satisfied. For example:

switch ( grade )

{

case 'A' :

Console.WriteLine ( "In A" ) ; case 'B' :

Console.WriteLine ( "In B" ) ; case 'C' :

Console.WriteLine ( "In C" ) ; case 'F' :

Console.WriteLine ( "In F" ) ;

}

This statement gives an error. This happens because of absence of the break statement. In C and C++, if such a switch statement is written we do not get an error. Instead the cases present after the one that gets satisfied are executed. In C#, if we want some other case to get executed after the one that gets satisfied then we must explicitly use a goto statement as shown below:

switch ( grade )

{

case 'A' :

Console.WriteLine ( "In A" ) ; goto s1:

case 'B' :

Console.WriteLine ( "In B" ) ; break ; case 'C' :

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

s1:

Console.WriteLine ( "In C" ) ; break ; case 'F' :

Console.WriteLine ( "In F" ) ; break ;

}

If we want that the same code should get executed if any of the two cases is satisfied then we can write the following code:

case 'a' :

case 'A' :

Console.WriteLine ( "In A" ) ;

In this example since the case 'a' is empty there is no need for a break statement in it. The switch statement can check integer, character and string types.

foreach Loop

The foreach statement lets us iterate over elements in arrays. If we want to iterate through an int array arr we can do so through the following statements:

int[ ] arr = { 1, 2, 3, 4, 5 } ; foreach ( int i in arr )

{

Console.WriteLine ( i ) ;

}

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: Registry

The registry is used to store information about Windows setup, user preferences, and installed software and devices. All the COM components place their CLSIDS, ProgIDs, paths of the DLLs, versions in the registry. This helps the clients to load the component from any directory. The registry is a hierarchical structure whose top-level nodes represent the registry hives. To view or modify the registry we execute the utility regedit through Start | Run Dialog.

The number of hives in the registry is fixed. There are seven of them. We cannot see all the hives.

HKEY_CLASSES_ROOT - Contains details of the types of files present on the system and information about applications that are able to open those files. It also consists of registration information for all COM components.

HKEY_CURRENT_USER - Contains details of user preferences for the user currently logged on to the machine.

HKEY_LOCAL_MACHINE - Contains details of all software and hardware installed on the machine.

HKEY_USERS - Contains details of user preferences for all users.

HKEY_CURRENT_CONFIG - Contains details of configuration of hardware devices on the machine.

HKEY_DYN_DATA - Contains information about volatile data.

HKEY_PERFORMANCE_DATA - Contains information concerning the performance of running applications.

Each root key consists of data as well as keys. The data is present as values. The value is divided into 3 parts: name, type and data. The key may have a default value, which is unnamed. The type of value may be formatted as one of the three data types namely, REG_SZ, REG_DWORD, REG_BINARY.

REG_SZ corresponds to a string.

REG_DWORD corresponds to a uint.

REG_BINARY corresponds to an array of bytes.

The .NET Framework offers two classes in the Microsoft.Win32 namespace: A RegistryKey class and a Registry class. Microsoft.Win32 namespace contains classes related to those that handle events raised by the operating system and those that manipulate the system registry. These classes are not included in the System namespace because they are specific to Windows operating system.

The RegistryKey class represents a Registry key. This class has methods to browse, to create new keys and to read or modify the values in the keys.

The Registry class contains only seven public static fields, which expose the actual keys to the programmer. These fields are read-only fields and cannot be modified. These fields expose the instances of the root RegistryKeys found in the registry. The seven fields are CurrentUser, LocalMachine, ClassesRoot, Users, PerformanceData, CurrentConfig, and DynData . This class is never instantiated and it only provides us with instances of top-level registry key instances.

Creating a Test Version Application.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

In the following program we plan to write an application that keeps a count on the number of times the application has executed as well as the amount of time the program spent in execution. If the application crosses a specified limit, it becomes unavailable. Many softwares, especially the ones that we download freely from the Net have an expiry period. When we run such softwares a dialog is popped up which informs us that we can use the software only for a specific number of days. And this count keeps reducing every day.

In our program we have kept a limit on number of days as well as time. The Logic used is as follows:

When we run our application for the first time, we add a registry entry in the HKEY_CURRENT_USER | Control Panel. Hence we have added a key for our application along with two values, one for maintaining the number of executions and another for maintaining the count on time.

Next time when we open the application it checks these values and accordingly allows or disallows the program to execute. The limitation that we have kept in the program is that it should work for a maximum of 5 hrs or can execute only 50 times.

To keep a count on time, we have added a timer control in our application. This is done by dragging in the control from the toolbox. We have changed its name from timer1 to mytimer.

Every time we start the application a 'staring form' is displayed which indicates the time expired, time remaining, number of times the application was executed, and remaining number of times it can be executed.

executed, and remaining number of times it can be executed. Here we have added 9 labels,

Here we have added 9 labels, 4 for displaying the static text and four for displaying the time expired, time left, executions completed, and executions remaining. We have named them as texp, tleft, execom, and exerem respectively. The last label is used to display a message besides the start button. The start button indicates that the actual application will start, the earlier form is just a starting indication, and it does not start the real application. When we click the start

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

button, the timer starts and number of executions increases by one.

But before this we have to add in registry entries. We plan to add our key in the HKEY_CURRENT_USER | Control Panel. We can add this somewhere else also. We have done this in the constructor of the form.

We have added the following data members to the form

RegistryKey top, r, demo ; int min, numexe, timercounts ;

In top we will have the RegistryKey instance of HKEY_CURRENT_USER key. In r we will have instance of Control Panel key and in demo we will have the key of our application. min will contain a count of minutes, numexe will contain a count of number of executions and timercounts will contain a count on seconds.

public Form1( )

{

 

InitializeComponent ( ) ;

top = Registry.CurrentUser ;

= top.OpenSubKey ( "Control Panel" , true ) ; demo = r.OpenSubKey ( "softdemo" , true ) ;

r

if

( demo == null )

{

 

demo = r.CreateSubKey ( "softdemo" ) ; demo.SetValue ( "Minutes", ( object ) min ) ; demo.SetValue ( "Executions", ( object ) numexe ) ;

 

}

 

else

 

{

 

min = ( int ) demo.GetValue ( "Minutes" ) ; numexe =(int) demo.GetValue ( "Executions" );

 

}

texp.Text = min / 60 + " hours " + min % 60 + " minutes" ; int m = 300 - min ; tleft.Text = m / 60 + " hours " + m % 60 + " minutes" ; execomp.Text = numexe + " " ; exerem.Text = 50 - numexe + " " ; msg.Text = " Click Start Button To Start Application " ;

if

( numexe >= 50 || min >= 300 )

{

 

msg.Text = "Trail Version expired" ; start.Enabled = false ;

 

}

}

Firstly we have collected the top-most RegistryKey in top using the Registry.CurrentUser field of the Registry class. Next we have initialized r with the key of Control panel using the OpenSubKey( ) method. Then we have initialized demo with the key of our application using the same function. If we get a null in demo, it means that this is the first time the application is running and no key is present. In this case we have added a new sub-key using the CreateSubKey( ) method. To this key we have added two values Minutes and Executions and have set both the data fields to 0 using the SetValue( ) method. The SetValue( ) method takes the second parameter as an object and hence we have type-casted it.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

If demo does not contain a null it means that the application is not running for the first time and the key and its values already exist. In this case we have retrieved the values using the GetValue( ) method. While retrieving the value we have to type cast it back in whichever data type we have used amongst a string, an int or a byte array. Here we have used an int. Next we have set all the text fields of the labels to the appropriate values by calculating the time in hours and minutes from the extracted key values. If the extracted minutes happened to be more that 300 (5 hours) or the number of executions happened to be more that 50, we have disabled the start button and flashed an appropriate message.

We have kept a count on time with the help of the timer. The timer starts when we click the Start button:

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

{

numexe++ ; demo.SetValue( "executions", ( object ) numexe ) ; mytimer.Start ( ) ; MessageBox.Show ( "Write Your Application Logic Here" ) ;

}

When we press 'Start' the number of executions is increased and the new value is set. We have added the Tick( ) handler with a time interval of 1000 milliseconds. This means after every 1000 milliseconds (1 second) this event will be fired. We can change this value in the 'Properties' window of the timer control. This is the place where we can write the logic of our actual application.

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

{

 

if ( ++timercounts >= 60 )

{

min++ ; texp.Text = min / 60 + "hours " + min % 60 + "minutes" ; int m = 300 - min ; tleft.Text = m / 60 + "hours " + m % 60 + "minutes" ; demo.SetValue ( "Minutes", ( object ) min ) ; timercounts = 0 ;

}

if ( min >= 300 )

{

mytimer.Stop ( ) ; Dispose ( ) ;

}

}

Here we have first checked if timercounts is greater than 60 (1 min). If it is, we have increased min by one and we have written the new value in the registry as well as in the text filed of the labels accordingly. Next we have checked the min field. If it happens to be greater than 300 (5 hours), the timer should stop and the program should terminate. To do so, we have called the Dispose( ) method. In this method we have disposed all the objects we created.

protected override void Dispose( bool disposing )

{

top.Close ( ) ; r.Close ( ) ;

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

demo.Close ( ) ; if ( disposing )

{

if ( components != null )

{

components.Dispose ( ) ;

}

}

base.Dispose ( disposing ) ; if ( min >= 300 || numexe >= 50 ) MessageBox.Show ( "You can no more use this software, time elapsed!!!!" ,"Sorry" ) ;

}

Here we have checked the min and numexe values and if they exceed the specified limit we displayed a dialog box with an appropriate message.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Article: DirectX - Direct Is Better

Hats off to the game developers of DOS era! They suffered so much and complained so little. To be able to write a game they were required to know what colors are available on the PC, how to produce them, how much memory does the PC have, what are the sound capabilities of the PC, which video card is installed in the PC, which different graphics mode does it support, what are the input devices attached to the machine, etc. But they were brave people. They acquired this knowledge and used assembly language and later C to develop games that met user's taste and demands.

One day all this changed. That was when Microsoft Windows operating systems came into being. No longer were the programmers required to worry about the new and changing capabilities of graphics cards, joysticks, graphics accelerators, etc. Now the game programmers were not required to spend time in creating and understanding the hardware specifications of display adapters. They could rely on Microsoft to do all that for them and package it for their use in the operating system. This was a big step forward. Still the game programmers were not happy to change from DOS to Windows as their game development platform. This was because though Windows could make it easier to develop games it stifled the creativity of the game designer and compromised the performance of the game by not letting the programmer have a direct access to the device capabilities. No longer was the scrolling smooth, the animation crisp and the sound explosive. So much so that many game developers simply abandoned the idea of using Windows as their game development platform. They continued their game programming in DOS and simply used Windows capability to shell out to DOS.

Such are the times that separate men from the boys. Microsoft didn't get disappointed with the lukewarm response that Windows received from game programmers. Microsoft knew that their strategy was right. They simply had to ensure that the performance of their model should be improved to match the performance that the game programmers had become accustomed to in DOS. Microsoft went back to the drawing board and came up with a Game Software Developer's Kit (Game SDK). This was the first version of DirectX. It consisted of fast, low-level libraries that did not impose constraints on the game design. It met and at times even exceeded the performance of DOS. Lastly, DirectX ensured that the burden of hardware support shifted from the developers to the hardware manufacturers. After all, the hardware manufacturers were eminently capable of creating drivers for their products and it was their responsibility to make the latest advance in their hardware accessible to the developers.

As the years have gone by DirectX too has evolved and has continuously increased its capabilities. Today it boasts of network support, force-feedback support and 3D graphics capabilities. So much so that it is no longer being used only for writing games, though that remains its predominant use. It is now also being used to show off your latest products, to create a virtual stereo to listen to the difference in types of sound systems that companies offer, to create screen savers and to build applications like instant messenger and voice chat that allows users to talk with one another on the internet.

What's Direct In DirectX

DirectX has been based on the philosophy of 'Directness'. There is no beating around the bush. It understands that all said and done if DirectX doesn't provide speed and takes the approach "we know what is best for you" there won't be many takers for it at the end of the day. It achieves its directness through:

Speed

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

To achieve speed DirectX uses the hardware features where they are available and emulates them where they are not available. For example, if hardware provides a operation like memory swap DirectX uses this feature thereby allowing the developer to get maximum out of parallel architecture that multimedia hardware can provide.

Reduced Latency

If we hit a key in a Windows application a message called WM_KEYDOWN is sent to the message queue of the application. When its turn comes the message is picked up from the queue and then processed by calling a suitable function. This process has been abstracted away from the programmer and he is required to bother only about the functionality that must be provided in the function that would get called when the key is pressed. This is all very good for normal Windows application, but it is a strict no no for game programming. Imagine a typical situation in a 2-player game. If one user places a punch on your nose, you would want to square it off right there. In this situation it would be unacceptable if Windows takes a long time to process your keyboard message. DirectX attempts to reduce this latency between "thinking of doing" and "actual doing".

Non-Interference

While building a library, one is often tempted to do things in a way one thinks is right and best. This can be dangerous and counter-productive. For example, if DirectX evolves a communication model that works same for a car-racing game and for a Chinese-checker game it would be inappropriate because the communication requirements of these games are different. So DirectX doesn't try to generalize things and provide automatic models for different gaming operations. Instead, it concentrates on the basics and seeks to enrich Windows by providing a set of low-level tools for building better games and multimedia applications. It does the basic operations well and leaves it to the imagination and innovativeness of game developers to exploit these features for their gaming product. Fair enough!

Components Of DirectX

DirectX made its debut as a Game SDK. But this SDK had a life span of only one version. There are a lot of 'DirectSomethings' in existence today. The chart Figure 1.1 shows their names and the subsequent discussion explains their purpose.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com DirectX Components DirectX Graphics This component includes various functions

DirectX Components

DirectX Graphics

This component includes various functions that are used for handling graphics. This component is further divided into DirectDraw (2D Graphics) and Direct3D (internally uses DirectDraw). The DirectX Graphics component also includes Direct3DX utility library which helps in simplifying complex mathematical operations useful to Direct3D.

DirectInput

This component supports variety of input devices like keyboard, mouse, joystick, etc. It also provides force-feedback effect in input devices like motor mounted joystick by generating push or resistance. Force-feedback technology helps make the gaming environment more realistic. For example, if we are flying an aircraft in a game and if the aircraft crashes then due to force- feedback we would feel the jerkiness of the explosion. (push effect) . Or if we are driving a car with the help of a force-feedback joystick, the more we push the joystick the more the car accelerates. If the car collides with another car/obstacle then the joystick will try to resist our action of pushing to simulate an obstacle. DirectInput removes delay in receiving input data by bypassing the Windows messaging architecture.

DirectX Audio

This component consists of DirectSound and DirectMusic. DirectSound is used to generate sounds like car doors slamming, horns honking and birds chirping thereby making games more realistic. It also removes delay in generating sound effects. DirectMusic is used to compose music at runtime.

DirectPlay

This component facilitates multi-player gaming on the network or Internet. It provides functionality

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

needed to organize and launch a multi-player game. This component can also be used to create messaging applications similar to MSN Messenger Service.

DirectShow

This component is used to playback multimedia streams like MPEG, AVI, WAV, QuickTime, etc, from local files or Internet servers. Using this component we can create variety of effects that are seen in PowerPoint and many more such applications.

DirectSetup

This component enables us to distribute DirectX runtime with our application. With this component our application can be packaged into a nice setup program. When it is installed all the libraries and support files are available when the user needs them.

Article: C# - Shared Assemblies

In the article on 'Assemblies' we saw how to build a private assembly. We shall extend that discussion and see how to build and use shared assemblies this time. We will convert the same assembly we made last time into a shared assembly. Recall that a private assembly is private to an application and every application using it has its own copy of the assembly. There is no need for the private assembly to be unique. A shared assembly on the other hand is available to all clients and hence must be unique.

To be uniquely identified, a shared assembly must have a strong name. The combination of a file name, a public key, a version number and culture gives an assembly a strong name, which is guaranteed to be unique. To understand these terms we must first know what is a public and private key.

Public Key Cryptography

Public and private keys are nothing but algorithms used for encryption and decryption of data. The main principle used in public / private encryption / decryption is as follows:

If something is encrypted using a public key, it can be decrypted using the corresponding private key, but not with the public key. This also works the other way round too, i.e. if something is encrypted using a private key it can be decrypted using the corresponding public key, but not the private key.

Public and private keys are always created in pairs. The public key is made available to everybody and the private key is kept safe and secure.

How it works on Assemblies?

First a public-private key pair is generated at random for the assembly using the sn utility. How to generate the keys using the sn utility is discussed later. We then provide these keys to the compiler. The compiler takes a cryptographic hash of the names and contents of the files in the assembly. This hash is taken using a very simple algorithm. This cryptographic hash is then encrypted using the private key for the assembly by the compiler, and placed in the manifest.

The compiler also creates the strong name and writes it in the manifest. As said earlier a strong name consists of a combination of a file name, a public key, a version number and culture. So along with the strong name the public key also gets written in the manifest. The strong name does not contain the private key. This ensures that the private key is not written in the manifest

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

and hence not made available to everybody. So in all two things are written inside the manifest, the strong name and the encrypted hash of the names and contents of the files. This is called signing of assembly.

Whenever an application wants to load an assembly, the runtime decrypts the hash of the files using the assembly's public key. The public key is available as it is stored in the manifest as part of the strong name. Then the runtime reads the names and files of the assembly and calculates the hash for itself. These two hashes are then checked, if they match, the assembly is loaded or else its not.

Any changes made to the files in the assembly after it is installed will make the application not work because the calculated hash won't match with the decrypted hash and the runtime will not load the assembly. If somebody tries to change the manifest, the .NET runtime will again detect a problem and refuse to load the assembly.

All the shared assemblies available on a system are stored in a folder called the Global Assembly Cache. This store is located in the '<drive>:\Windows\Assembly' folder.

Using the sn utility

We plan to convert the same DLL i.e. fontassembly.dll into a shared assembly. To convert it into shared assembly we have to first use the sn utility (strong name utility). This utility generates a public / private key pair. The public key created using this utility will be used to define a strong name.

To create the key pair we must type the following on Command Prompt

C:\CSharp\fontassembly>sn -k mykey.snk

On executing the utility a file mykey.snk gets created. This file contains the public and private keys.

We must now use this file in our project. To do so open the 'AssemblyInfo.cs' file of the project. In this file we would have to set the AssemblyKeyFile attribute. The attribute must be set to an absolute path to the key file. Following are the changes ( shown in bold ) to be made in 'AssemblyInfo.cs'

[ assembly: AssemblyDelaySign ( false ) ]

[ assembly: AssemblyKeyFile ("mykey.snk") ]

[ assembly: AssemblyKeyName ( "" ) ]

We also have to change the version number of our assembly as shown below

[ assembly: AssemblyVersion ("1.0.1.1") ]

The reason behind this will be clear when we discuss versioning in the next article. On rebuilding this, the assembly along with the strong name associated with it gets created and also the encrypted hash is written in the manifest. This is known as signing of the assembly.

Installing the Shared Assembly

After signing the assembly, it's possible to install the assembly in the global Cache. To install a shared assembly in the global cache we have to use the Global Assembly Cache utility tool called the gacutil tool. At the command prompt we have to use it with a /i option. Here /i stands for install. This what we must type at the command prompt

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

C:\CSharp\fontassembly\bin\Debug>gacutil /i fontassembly.dll Microsoft (R) .NET Global Assembly Cache Utility. Version 1.0.2914.16 Copyright (C) Microsoft Corp. 1998-2001. All rights reserved.

Assembly successfully added to the cache

We can now open the Global assembly cache and we will find that our assembly gets added to it as shown in following figure.

our assembly gets added to it as shown in following figure. Using the Shared Assembly We

Using the Shared Assembly

We will use the same client we made last time for using 'fontassembly.dll'. To do so first we have to be sure of two things: We must delete the private 'fontassembly.dll' version we created last time from the directory of the client and secondly we must remove its reference by right clicking on fontassembly under 'References' in the 'Solution Explorer' window and selecting 'Remove'.

To use the shared assembly we will have to again add the reference of the shared assembly in the same way as for the private assembly. But this time the assembly does not get copied into the local directory because the CopyLocal property of the reference is automatically set to False by the compiler. This can be seen in the 'Properties' Window of the assembly.

On compiling the client we get the same results. We can now use the same DLL in any client we want and every time the assembly installed in the Global cache will be used.

Structure of an Assembly

So now lets look at how the assembly looks like. The assembly is made up of metadata , IL code and resources. The Metadata consists of type metadata and assembly metadata.

Assembly Metadata describes the assembly and is called the Manifest. A manifest contain:

a. The identity of the assembly, consisting of its name, version and culture.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

An assembly has a four part version number e.g. 1.0.1.1. The parts are

<Major> . <Minor> . <Build> . <Revision>

The use of these numbers is dependent on the configuration of our application. If the new version created is compatible with the older version we must not change the major or minor numbers. On the other hand if the versions are incompatible we must change the major and minor numbers. The build number is the number of days since Jan-1, 2000, and revision is the number of seconds since midnight local time. Culture is

b. Names of all the files in the assembly.

c. Details of all the types defined in the assembly.

d. Whether all the types defined in the assembly are visible to other assemblies or private to one.

e. A hash of all files in the assembly

f. Names and hashes of other assemblies that an assembly in turn will need to reference when run

g. Details of any security permissions that clients need to have in order to be able to run the assembly

Type metadata consists of metadata describing the exported types and methods. To view the assembly and manifest Microsoft has provided us with the ILDASM tool.

The ILDASM Tool

The ILDASM, the MSIL disassembler, is used to view assemblies. We can run this tool by starting ildasm from the command line, with the assembly as argument or by selecting the 'File / Open' menu.

This is how the ildasm window looks after opening our 'fontassembly.dll' in it:

looks after opening our 'fontassembly.dll' in it: The tool shows the Manifest, Namespace, Class and Method

The tool shows the Manifest, Namespace, Class and Method in the assembly. It can also show Interfaces, Value types, Static methods, Fields, Static Fields, Events and Properties if present.

Article: C# - Versioning

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Continuing the analysis of Assemblies from the last article, we shall see how you use the new features to solve versioning problems. With DLLs, a new version would always overwrite the older version breaking the clients using the older version. Assemblies bypass this problem.

We never do versioning on private assemblies. Every client has its own copy of the private assembly and installing a newer version would mean overwriting the existing version. This would not affect or break clients using the older version because they would still have their copy of the older version in their local directories.

Versioning is always done on assemblies with strong names i.e. shared assemblies. We can install multiple versions of the same assembly in the Global Cache simultaneously. The older versions do not get overwritten and hence clients using the older version do not fails. If we want we can also redirect old clients to start using the new version. This is all done with the help of configuration files.

Last time we had created an assembly and stored it in 'fontassembly.dll'. What we plan to do here is to create a new version of 'fontassembly.dll'. To do so we would have to create a new copy of the code and make the following change in 'Class1.cs' file.

Font myfont = new Font ( fname, size, FontStyle.Italic ) ;

And the following in 'AssemblyInfo.cs' file.

[ assembly: AssemblyVersion ( "1.1.1.1" ) ]

On rebuilding this, the assembly along with a strong name associated with it gets generated. Next we have to install this version in the Global assembly cache. This is done using the gacutil tool. After installing it in the Global assembly cache we find that both the versions of 'fontassembly.dll' (1.0.1.1 and 1.1.1.1) stand installed.

(1.0.1.1 and 1.1.1.1) stand installed. Figure 1 : Global Assembly List Now client applications can

Figure 1 : Global Assembly List

Now client applications can be created that use any of the two versions installed. We just have to add a reference of the assembly we want to use.But this leaves us with one question. What about already existing clients who want to shift to a newer version without being recompiled? The answer is redirection.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

We can specify redirection in a configuration file of the client. We will have to first create a configuration file for that. With the configuration file we can specify that the binding should happen to a different version of a shared assembly without rebuilding the client application. To achieve this .NET provides us with a .NET Admin Tool which is a MMC Snap-in called 'mscorcfg.msc'. It is present in the C:\WINNT\Microsoft.NET\Framework\v1.0.2914 directory.

in the C:\WINNT\Microsoft.NET\Framework\v1.0.2914 directory. Figure 2 : .Net Admin Tool To create a configuration file we

Figure 2 : .Net Admin Tool

To create a configuration file we will have to right click on 'Applications' on the left side, choose 'Add' and select 'fontclient.exe'. The .NET Admin Tool shows all the dependencies of the selected assembly. Also, we here we can alter and configure the dependencies of of the assembly from the dependency list. The list shows assemblies our client depends on. The highlighted entry in the following figure is the version of 'fontassembly.dll' that our client is using presently.

that our client is using presently. Figure 3 : Default Assembly Versions We plan to request

Figure 3 : Default Assembly Versions

We plan to request for a new version. To do so we have to right click on 'Configured Assemblies' and select 'Add'. Next we have to select 'Choose an assembly from the assembly cache' and click 'Choose Assembly'. Then select 'fontassembly.dll' with the new version and click 'Select'. On selecting 'Finish' we get the 'Properties' sheet. In this sheet we will have to specify the old and new version of 'fontassembly.dll'.

Now we can find an application configuration file 'fontclient.exe.config' in the directory of the 'fontclient.exe'. The 'fontclient.exe.config' file that gets created is in XML format is as shown below

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-

microsoft-com:asm.v1">

<dependentAssembly> <assemblyIdentity name="fontassembly" publicKeyToken = "a97ce0a468973397" /> <bindingRedirect oldVersion="1.0.1.1" newVersion="1.1.1.1" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>

When we run the client with this configuration file the redirected version 1.1.1.1 is used instead of the older version.

Article: C# - Events And Delegates - I

Each action the user makes such as clicking the mouse button, selecting a menu item, pushing a button, etc. raises an event. Events notify that something has happened, as a result, some action should take place. The action is performed in a method called an event handler. All the event handlers are called with the help of delegates. Hence to understand events and event handlers we must first know what delegates are.

Delegates

We normally pass a value or a reference of an object to a method. Situations may arise where we may need to pass an address of some method to another method. This was done previously with the help of function pointers. This approach is not type safe and certainly not object-oriented.

C#'s alternative for function pointers is delegates. Here, the word delegate means a representation of a function. A delegate is implemented as an object that stores address of method in it. The class of this object is called a delegate class and is derived from System.MulticastDelegate class.

To store the address of a method,

bool fun ( string )

{

}

in a delegate we have to carry out two steps:

a. Declare a delegate class

b. Create a delegate object and store the address of the method in it

Declaring A Delegate Class

Here is a single delegate class declaration

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

public delegate bool del1 ( string ) ;

When the compiler encounters this statement it creates a class named del1 and derives it from the System.MulticastDelegate class. The compiler also inserts a two-argument constructor in the del1 class. Note that we are never required to define a delegate class.

Later when an object of the delegate class del1 is created, it can hold address of a method that receives a string and returns a bool.

Creating A Delegate Object

To store address of the fun( ) method inside a delegate object need to first create a delegate object. This is how it can be done.

del1 f = new del1 ( fun ) ;

Here f is a reference to an object of del1. The address of the fun( ) method is passed to the constructor of the delegate class which is created by the compiler. The constructor stores this address in the delegate object. To call the wrapped method we can write the following statement:

bool b = f ( "Hi" ) ;

Here f delegates (represents) fun( ) in true sense.

Delegates are very flexible. It does not matter whether the method to be wrapped by the delegate is a static method or an instance method. Also, these methods can belong to any class. Consider the following program:

using System ;

namespace Sample

{

public delegate void click( ) ;

public class MyForm

{

public click c1 ;

public void mouseclick( )

{

}

}

c1( ) ;

class MyForm1 : MyForm

{

public MyForm1( )

{

c1 = new click ( MyForm1_click ) ; mouseclick( ) ;

c1 = new click ( button_click ) ; mouseclick( ) ;

}

static void Main ( string[ ] args )

{

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

MyForm1 f = new MyForm1( ) ;

}

public void MyForm1_click( )

{

Console.WriteLine ( "Form clicked" ) ;

}

public static void button_click( )

{

Console.WriteLine ( "Button clicked" ) ;

}

}

}

In the above program we have declared a delegate class called click. Later when an object of this class is created it can hold address of any method that does not accept or return anything.

We have created two classes in the program: a MyForm class and a MyForm1 class derived from MyForm. The MyForm class contains a reference c1 of the type click and a method called mouseclick( ).

Besides the zero argument constructor and Main( ), the MyForm1 class contains an instance method called MyForm1_click( ) and a static method called button_click( ). Both MyForm1_click( ) and button_click( ) methods are eligible to be wrapped inside the delegate object, because prototypes of both the methods match the prototype mentioned in the delegate declaration.

In Main( ) we have created an object of the MyForm1 class resulting in the constructor being called. In the constructor we have stored the address of the MyForm1_click( ) method in the reference c1. Thus, c1 delegates (represents) the method MyForm1_click( ). Next we have called the mouseclick( ) method which in turn calls the MyForm1_click( ) method via c1.

The next statement in the constructor makes c1 to refer to the static method and hence a call to the mouseclick( ) method results in calling the static method.

This program was a little odd but it would help you to understand the event-handling model of WinForms programming in C#.

Multiple Methods In A Delegate

A delegate can wrap even more than one method. For this, it maintains a linked list. The delegate then points to the head of such a linked list. This means that when such a delegate is invoked it calls all the methods that form the linked list.

Hence, instead of the statements

c1 = new click ( MyForm1_click ) ; mouseclick( ) ; c1 = new click ( button_click ) ; mouseclick( ) ;

we can simply write

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

c1 += new click ( MyForm1_click ) ; c1 += new click ( button_click ) ; mouseclick( ) ;

The delegate c1 inside the mouseclick( ) method would now call both the methods. Here we are simply adding both the methods in a list and hence both would be called. Rest of the program remains same.

Events

As said earlier, the Windows GUI programming requires that the program must respond to events. An event in C# is a multicast delegate having a predefined prototype. The prototype is such that every event (actually a multicast delegate) would, by convention return a void and always accept two parameters. The first parameter is always a reference to an object of System.Object class and the second parameter is always a reference to an object of the System.EventArgs class or a class derived from it. The EventArgs object contains information about the event.

The object that raises an event is called an 'event raiser' and the object that receives an event is called an 'event receiver'. Whenever an event is raised a method is called that handles the event (hence called an event handler). The event raiser class always declares the event and the receiver class must have an event handler to handle that event. The first parameter collected by the event handler is always a reference to an event raiser object. The addresses of event handlers are stored inside the events (remember that events are actually delegates) and hence they also must have the same signature as the event. Such kind of a delegate is declared using the keyword event.

Article: C# - Events And Delegates - II

Continued from last week

To understand events, consider the following program:

using System ;

namespace Sample

{

public class mouseeventargs

{

 

public int x, y ;

public mouseeventargs ( int x1, int y1 )

{

x = x1 ;

y = y1 ;

}

}

public delegate void click ( object m, mouseeventargs e ) ;

public class MyForm

{

public event click c1 ;

public void mouseclick( )

{

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

mouseeventargs m = new mouseeventargs ( 10, 20 ) ; c1 ( this, m ) ;

}

}

class MyForm1 : MyForm

{

 

public MyForm1( )

{

c1 += new click ( button_click ) ; mouseclick( ) ;

}

static void Main ( string[ ] args )

{

MyForm1 f = new MyForm1( ) ;

}

public void button_click ( object m, mouseeventargs e )

{

Console.WriteLine ( "Mouse Coordinates: " + e.x + " " + e.y ) ; Console.WriteLine ( "Type is: " + m.GetType( ).ToString( ) ) ;

}

}

}

The output of the program would be

Mouse Coordinates: 10 20 Type is: Sample.MyForm1

In this program we have declared 3 classes-mouseeventargs, MyForm and MyForm1 derived from MyForm. The mouseevntargs class corresponds to the EventArgs class. This class contains two int variables x and y and a constructor to initialize them. We have declared a multicast delegate click whose signature is same as the event handler button_click( ). The MyForm class here is an event raiser class and hence contains an event as a data member called c1 of the type click. It also contains a method called mouseclick( ). In this method we have created an object of the mouseeventargs class. In the statement,

c1 ( this, m ) ;

c1 represents (is a delegate for) button_click( ). this contains the reference of MyForm object (event raiser) and m is a reference of the mouseeventargs object. In the MyForm1 class, we have defined the method button_click( ) (i.e. event handler). When the compiler encounters the statement

c1 += new click (button_click)

it creates an event object (delegate object) that wraps up button_click( ) method. So whenever the c1 event is raised (or called, as in this program), the method button _click( ) will get executed.

Now back to WinForms. WinForms event handling model follows the same arrangement that we discussed above. The difference is that Event programming in WinForms is very easy and we need not think about these underlying concepts every time. The Wizard automatically generates

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

code for us and we have to just write logic in the event handlers.

Let's take a look at what the wizard generates for us every time we add an event handler to our form. Create a 'Windows Application' which should display a message box when the user clicks on the form. The following code would get generated.

using System ; using System.Windows.Forms ;

namespace SampleClick

{

 

public class Form1 : System.Windows.Forms.Form

{

public Form1( )

{

InitializeComponent( ) ;

}

#region Windows Form Designer generated code private void InitializeComponent( )

{

this.Click += new System.EventHandler ( this.Form1_Click ) ;

}

#endregion

static void Main( )

{

Application.Run ( new Form1( ) ) ;

}

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

{

MessageBox.Show ( "Hello C#" ) ;

}

}

}

We have erased the comments and some extra code added by the wizard for the sake of clarity. We just have to type the code which is given in bold letters above and compile the program. On executing the program and clicking on the form we get the output as shown in Figure 1.

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Documents downloaded from www.funducode.com Figure 1 Here, Click is a reference to an event of the

Figure 1

Here, Click is a reference to an event of the type System.EventHandler and is already defined in the System.Windows.Form class. Realize that System.EventHandler is a delegate used to wrap an event handler. A delegate that dispatches an event is called an 'event delegate'. The event handler Form1_Click( ) is wrapped inside the Click event. This method is written in the Form1 class and it accepts two references. One of them is of object type and contains reference of the event raiser (Form1 here) and the other is of type EventArgs.

Here we have not written any statement to explicitly raise the event Click( ). Whenever the user

clicks on the form the .NET runtime raises this event for

class, Form about this event. The Form class would call the event handler using the statement like

.NET runtime then informs the base

us.

Click ( reference of sender, reference of EventArgs ) ;

Here, Click represents (is a delegate for) Form1_Click( ) event handler. And so, this statement would call the Form1_Click( ) handler.

Article: C# - Properties And Indexers - I

Bashing Structured paradigm and glorifying OO has been the computing industry's favourite past time for almost a decade now. OO programming has also grown old now. Today is the era of modern OO languages, which take the OO paradigm further. Properties, indexers and events are first class citizens of modern OO languages like C#.

Nothing great if C# supports encapsulation, inheritance and polymorphism. It being an OO language this was expected of it. It being a modern OO language, it supports features like properties, events, indexers, delegates etc. Of these this article would cover properties and indexers.

Properties

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Properties of a class are actually methods that work like data members. We have already used the Length property of the System.Array and System.String class in an earlier article. The properties are used to store and retrieve the values to and from the data members of the class. For example, to store and retrieve the length data member of the string class the Length property is used. Conventionally the data members are given names starting with a lower case letter and the corresponding properties are given names starting with a capital letter.

Manipulating data using properties is done through two special methods known as accessors. There can be two accessors: a get accessor and a set accessor. The following code shows both of them.

using System ;

namespace properties

{

 

public class sample

{

int length ;

public int Length

{

get

{

return length ;

}

set

{

length = value ;

}

}

}

class Class1

{

static void Main ( string[ ] args )

{

sample m = new sample( ) ;

m.Length = 10 ; int len = m.Length ; Console.WriteLine ( "Length: " + len ) ;

}

}

}

Here we intend to access and modify the length data member of the sample class. Since it is of the type int we have used public int Length to declare the property to be of the type int. As a result, the get accessor would return an int type and the set accessor would collect the int type. The get accessor never accepts any value and the set accessor never returns any value. The value collected by the set accessor is stored in an implicit parameter called value. value is a keyword and would always have a type corresponding to the property. We should be careful not to give any data member a name value. The statement m.Length = 10 would invoke the set accessor automatically. The statement int len = m.Length would invoke the get accessor automatically.

In general the get accessor is invoked when we want to retrieve the value of the property, whereas the set accessor is invoked when we assign a value to the property. We cannot explicitly

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

call the accessors using the get and set keywords.

If only get accessor is present the property is called a read only property. If only set accessor is present then the property is called a write-only property. If both accessors are present, the property is said to be a read-write property. If we write a statement,

m.Length = m.Length + 20

both the get and set accessors would get called. When the addition operation is performed the get accessor would get called. The get accessor will return the value of length. Next 20 would be added to it. Now using the set accessor, the resulting value would be assigned to length.

A Few Subtleties

Let us now look at a few subtleties associated with accessors:

a. The advantage of using properties as against public data member is that if we want, we can perform some functionality in the accessor body. For example, we can check range for the length variable in the set accessor as shown in the following code snippet.

set

{

if ( value > 10 ) length = value ;

}

b. If we derive a class from a base class which has a public property declared in it, the object of the derived class can also access the property of the base class. If the property of the base class is declared as virtual the derived class can override the base class property with its own version of the property.

c. Properties can also be declared abstract. If we declare the property as abstract, it is necessary to declare the class containing the property as abstract. Since we cannot create the objects of the abstract class, it becomes necessary to derive a class from it and implement the property. For example, in the following program the class dimensions has one abstract property Height.

public abstract class dimensions

{

 

protected int height ;

public abstract int Height

{

get ;

set ;

}

}

To declare the property abstract we have to write the get and set keywords without any accessor body. The derived class must implement the property as shown below.

public class window : dimensions

{

public override int Height

{

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

get

{

 

return height ;

}

set

{

 

height = value ;

}

}

}

d. The static modifier can be used to create properties that belong to a class and not to an individual object. We can write static properties for static data members only. To access these properties we have to use the class name instead of an object. For example,

using System ;

namespace sample

{

 

public class window

{

static int height ;

public static int Height

{

 

get

{

return height ;

}

set

{

height = value ;

}

 

}

}

class Class1

{

static void Main ( string[ ] args )

{

 

window.Height = 10 ; Console.WriteLine ( "Window height: " + window.Height ) ;

 

}

}

}

e. A class can contain multiple properties.

Article: Properties And Indexers- II

Continued from last week

Indexers

An Indexer is a special type of property. If a class contains an array as a data member, an indexer lets us access the array within the class using an object as though the object itself were an array. This is done using the [ ] operator. For example, consider a class myclass which has an

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

int array as a data member and we create an object a of that class. Here we can access the elements of the array by using the expressions a[0], a[1], a[2] and so on. The following code snippet shows how to declare an indexer:

public int this [ int index ]

{

 

get

{

 

// code

 

}

set

{

 

// code

 

}

}

Like properties we use the get and set accessors in indexers. The difference between a property and an indexer is that an indexer is nameless. This means it does not have a name like Height, Length, etc. instead the this keyword is used to declare an indexer. The this reference refers to the object we are indexing. The first int in the indexer declaration specifies type of the array. The second int within the square brackets specifies the type of argument we would be using to index into an array. The following example shows how we can make an object behave like an array:

using System ;

namespace sample

{

 

public class array

{

float[ ] arr = new float [ ] { 12.5f, 34.3f, 5.2f, 6.1f, 7.5f, 88.8f, 22.9f } ;

public float this [ int index ]

{

get

{

return arr [ index ] ;

}

set

{

arr [ index ] = value ;

}

}

}

class Class1

{

static void Main ( string [ ] args )

{

array a = new array( ) ; a [ 3 ] = 43.2f ; Console.WriteLine ( a [ 3 ] ) ;

}

}

}

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

Here arr is a float array and it belongs to the same class in which we have declared the indexer. When we write the statement a [ 3 ] = 43.2f the set accessor gets called. The index 3 would get collected in the variable index and 43.2f would get collected in the variable value. When we write the statement,

Console.WriteLine ( a [ 3 ] ) ;

the get accessor gets called. The index 3 would get collected in the variable index and the element at fourth place would be returned.

We can also declare an indexer for a multi-dimensional array. In the following program we have used two indexers one for 1D array and another for 2D array. Such indexers are known as overloaded indexers.

using System;

namespace sample

{

public class array

 

{

int [ ] arr1 = new int [ ] { 12, 34, 5, 6, 7, 88, 22 } ;

int [ , ] arr2 = new int [ , ] {

 
 

{

12, 34, 5, 6 },

{

7, 88, 22, 2 }

} ;

public int this [ int index ]

 

{

get

{

 

return arr1 [ index ] ;

}

set

{

 

arr1 [ index ] = value ;

}

}

public int this [ int index1, int index2 ]

{

get

{

 

return arr2 [ index1,index2 ] ;

}

set

{

 

arr2 [ index1,index2 ] = value ;

}

}

}

class Class1

 

{

static void Main ( string[ ] args )

{

Compiled by rmshankar@yahoo.com

Documents downloaded from www.funducode.com

array a = new array( ) ;

a [ 3 ] = 43 ;

a [ 0, 2 ] = 89 ;

}

}

}

The two int variables specified within brackets in the statement,

public int this [ int index1, int index2 ]

Specify the two indexes used to access an element of the 2D array. When we write i [ 3 ] = 43 , the set accessor with one argument gets called and when we write i [ 0, 2 ] = 89, the set accessor with two arguments gets called. It is not possible to write indexers for jagged arrays because a statement such as public int this [ int index1] [ int index2 ] is an error.

Lastly, indexers can not be declared as static. Indexers work in the same way as properties when declared as virtual.

Article: C# - Arrays And Strings - I

Arrays and Strings are perhaps as old as programming languages themselves. They have been around for so long that they are almost taken for granted. Don't make this mistake while learning C#. In C# they are different and more powerful. That's bound to happen when a language is developed from ground up without being required to shoulder the responsibility of backward compatibility…

An array is a collection of similar elements stored in adjacent memory locations. These similar elements could be all ints, all floats, all chars, etc. For example,

int[ ] arr1 = { 1, 2, 3 } ; float[ ] arr2 = { 1.5f, 2.5f, 3.5f } ; char[ ] arr3 = { 'a', 'b', 'c' } ;

All elements of an array must be of the same type, i.e. we cannot have an array of 10 numbers, of which 5 are ints and 5 are floats. Arrays in C# are reference types and are implemented as objects. They are derived from the abstract class System.Array