Archive

Archive for the ‘C#’ Category

C# Tutorial : Lesson 15 – Error Handling

October 26th, 2007

There are three types of errors that can occur in your application. These are:-

  • Syntax Errors
  • Runtime Errors or Exceptions
  • Logical Errors

Syntax errors occur due to ill-formed codes. The cause can be a misspelled keyword, improperly constructed statements, absence of punctuations, such as line terminators, etc. The resulting code cannot be until all of these errors are removed.

Example:-

In this case the keyword Class is misspelled as Clas. Notice how the Visual Studio IDE highlights the error even before compilation starts. This is possible because of background compiling which is utilized in almost all modern Programming IDEs.

Runtime errors or Exceptions are erroneous situations in the runtime. The simplest example can be a division by Zero which results in a “Division by Zero” exception to be raised. These are different from Syntax errors in the sense that the compiler cannot detect these and hence the application compiles.

Click on the image to see the full screen version.

In the above program, the application halts due to a DivideByZeroException. Since, the compiler cannot determine the number that will be entered by the user, the error goes undetected. At runtime, the statement float Result = I / J; raises the DivideByZero exception, if the user enters 0 as the input for the second variable.

Logical Errors are those where the application compiles and runs properly but does not produce the required output, i.e errors in the logic of the program. They are harder to detect because they don’t throw any kind of exception. The best way to deal through them is to use the debugger, watches and call stacks.

Exceptions

System.Exception is the base class for all other exceptions. Below this level are the System.ApplicationException and System.SystemException classes which are derived from the System.Exception class.

The SystemException class acts as the base class for all the pre-defined Exceptions. ApplicationException class is to be used for any custom exceptions that you are to create in your application. Unlike the System Exceptions, these are forwarded by the application and not the CLR.

Below is a table listing some of the classes dervied from SystemException class.

Exception Class Description
System.IO.IOException Handles Input/Output errors
System.IndexOutOfRangeException Handles errors generated when a method refers to an array element, which is out of its bound.
System.NullReferenceException Hanldes errors generated during the process of dereferencing a null object.
System.DivideByZeroException Handles errors generated during the process of dividing a number by zero.
InvalidCastException Handles errors generated during typecasting.
OutOfMemoryException Handles memory allocation to the application errors.
Handling Exceptions

Exceptions are handled by using exception handlers. These exception handlers divide the code in blocks.

The try Block

All the codes that have a chance of throwing exceptions are put inside the Try block. Given below is a simple try block code.

try
{
    //Statements that may throw exceptions.
}

The catch Block

If any statement inside the try block throws an exception, the execution control is passed onto the appropriate catch block. This allows the application to recover from exceptions. Catch block follows the following syntax:-

catch (…)
{
//Error Handling Code
}

Note: Every try block must have an associated catch block and vice versa.

The following code would trap the exception thrown in the previous example.

try
{
    float Result = I / J;
}
catch
{
    Console.WriteLine("An error occured while trying to compute the result");
}

Whenever the user enters a value of 0 for J, an exception would be thrown. Since, this code is contained in a try block, the code inside the catch block will be executed and a message An error occured while trying to compute the result will be shown to the user.

In the above example, the type of exception being thrown is unknown. So, no matter what exception is thrown, the same message will be displayed.

You can specify the type of exception a catch block handles in the following way:-

try
{
    Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException)
{
    Console.WriteLine("You tried to divide the number by zero");
}

The catch block declaration can also instantiate an object of the corresponding Exception class providing access to exception specific information – Error Codes, Description, etc.

try
{
    Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException ex)
{
    Console.WriteLine(ex.Message);
}

The code given below is a modified form of the earlier example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Console.WriteLine("Enter Two Numbers:-");
int I = Convert.ToInt32(Console.ReadLine());
double J = Convert.ToDouble(Console.ReadLine());
int Result = 0;
try
{
    Result = Convert.ToInt32(I / J);
}
catch
{
    Console.WriteLine("An error occured while trying to compute the result");
}
Console.WriteLine("The result is {0}", Result);
Console.Read();

Line 8 can now generate two types of exception: DivieByZeroException and OverflowException. When the user enters a very high value, say 65536275 for the variable I and an extremely low value, say 0.0000001 for J. The result would exceed the range of the int datatype and the OverflowException would be thrown. Because the user would be treated with the same error message, he/she might not be able to determine the exact cause of the error.

This is where the catch block comes in handy. Multiple catch blocks can be attached to a try block. Each of them should differ in the type of exception they handle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Console.WriteLine("Enter Two Numbers:-");
int I = Convert.ToInt32(Console.ReadLine());
double J = Convert.ToDouble(Console.ReadLine());
int Result = 0;
try
{
    Result = Convert.ToInt32(I / J);
}
catch (DivideByZeroException)
{
 
    Console.WriteLine("You tried to divide the number by zero");
}
catch (OverflowException)
{
    Console.WriteLine("The operation resulted in an overflow");
}
catch(Exception)
{
    Console.WriteLine("An error occured while trying to compute the result");
}
Console.WriteLine("The result is {0}", Result);
Console.Read();

Now, if an OverflowException is thrown, the message The operation resulted in an overflow will be displayed. For the DivideByZero exception, the message You tried to divide the number by zero will be shown. For any other exception, the last message An error occured while trying to compute the result will be displayed.

Order of Catch Blocks

1
2
3
4
5
6
7
8
9
10
11
12
13
int A = 5, B = 0;
try
{
    A = A / B;
}
catch (Exception ex)
{
    Console.Write("Exception");
}
catch (DivideByZeroException ex)
{
    Console.Write("Divide By Zero Exception");
}

The order of the catch block is very important.

A series of catch statements needs to be in decreasing order of derivation. For example, the most derived objects must appear first.

The above code generates the following compile-error: A previous catch clause already catches all exceptions of this or of a super type (’System.Exception’).

If the catch(Exception) block is declared at the top, even a DivideByZeroException or the OverflowException will be handled by this block. This is because both of them are indirectly derived from the Exception class. Infact, C# does not allow such scenarios. So, you must first declare the exception class that is at a deeper level of the hierarchy.

The correct code would be as follows:-

1
2
3
4
5
6
7
8
9
10
11
12
13
int A = 5, B = 0;
try
{
    A = A / B;
}
catch (DivideByZeroException ex)
{
    Console.Write("Divide By Zero Exception");
}
catch (Exception ex)
{
    Console.Write("Exception");
}

The finally block
This block is used to execute statements which are to be executed regardless of whether the exception is thrown or not. This may include a code such as to close a file, an existing SQL connection, etc. Only one finally block can exist for a try block. Also, the finally block is optional.

One may argue as to why we need the finally block because all statements below the entire try – catch block will be executed, irrespective of whether an exception is thrown or not. However, the code in the finally block is executed, even if a return statement is encountered inside the try or the catch block. The same is not true for the codes following the try – catch block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int I = 10, J = 0;
 
float Result = 0;
try
{
    Result = I / J;
}
catch
{
    Console.WriteLine("An error occured while trying to compute the result");
    return;
}
Console.WriteLine("The result is {0}", Result);
Console.Read();

The output of the preceeding block of code would be:-

An error occured while trying to compute the result

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int I = 10, J = 0;
 
float Result = 0;
try
{
    Result = I / J;
}
catch
{
    Console.WriteLine("An error occured while trying to compute the result");
    return;
}
finally
{
    Console.WriteLine("The result is {0}", Result);
    Console.Read();
}

While, the output for this one would be:-

An error occured while trying to compute the result
The result is 0

Creating Custom Exceptions

User defined exceptions can be created by deriving from the System.ApplicationException class or from any other system defined class. You can also derive Exceptions from these user-defined classes. The ultimate thing is that the new Exception class should be derived (directly or indirectly) from the Exception class.

1
2
3
4
5
6
7
class MyException : ApplicationException
{
    public MyException(string Message) : base(Message)
    {
 
    }
}
Raising Exceptions

Use the throw statement to raise your exceptions. This process requires the creation of a new object of the appropriate Exception class.

throw new(MyException("My Exception was thrown"));

Even the system defined exceptions can be thrown in this fashion.

Never create and throw an object of System.Exception class

partho C#

C# Tutorial : Lesson 14 – File Handling

October 17th, 2007
Files & Folders

One of the ways of permanent storage of data is through files. A file is a collection of data stored on a secondary storage device, such as the Hard Disk. Every file has a name associated with it, such as Essay.txt. The name comprises of two parts the base name (in our case ‘Essay’) and the extension (txt). The portion before the period (.) is the base name whereas the one after it is the extension. A file name can also contain multiple periods – Dr. No.avi. The most significant period is always the last one. So, in this case, the base name of the file would be Dr. No and the extension avi.

The extension is what determines the type of the file. For example, a document has an extension of doc while a JPEG Image file has an extension of jpg. The base name is what we specify to identify that particular file.

Files are contained in folders or directories. A directory itself can contain other files and folders, thus forming a hierarchy. Files within a folder (directory) need to have unique names. Files with same base name but different extensions are allowed. So, the file My File.txt and My File.doc can co-exist in a folder. The full path of the file marks its complete address on a machine. For instance, if the file Notepad.exe is contained inside the Windows directory of your C drive, its path would be “C:\Windows\Notepad.exe”. Likewise, if it were to be contained inside the System32 directory which in turn is present in the Windows directory, the full path would be “C:\Windows\System32\Notepad.exe”.

Note: No two files on your computer can have the same full path.

Stream

A stream is a sequence of bytes travelling from a source to a destination over a communication medium. Streams can either be input or output. The input stream is used for reading while the output stream is used for writing.

Note: This stream concept does not just apply to files. It holds true for communication over a network through sockets too.

File System Classes

.NET provides a lot of classes for handling files. These are contained in the System.IO namespace. Listed below are various classes under this namespace.

Class Name Description
FileStream Is used to read from and write to any location within a file.
BinaryReader Is used to read primitive data types in the form of binary data from the stream.
StreamReader Is used to read characters from a byte stream.
StringReader Is used to read data from a string buffer.
BinaryWriter Is used to write primitive data types in the form of binary data to the stream.
StreamWriter Is used to write characters to a byte stream.
StringWriter Is used to write data to a string buffer.
BinaryReader Is used to read primitive data types in the form of binary data from the file stream.
StreamReader Is used to read characters from the a byte stream.
DirectoryInfo Is used to perform operations on directories.
FileInfo Is used to perform operations on files.
FileStream Class

The FileStream class resides under the System.IO namespace and is derived from the abstract class Stream. It supports random access through seeking. Before you begin reading from and writing to a file, an object of the FileStream class needs to initialized. The parameterized constructor of this class allows to create/open files and set up appropriate file sharing modes.

Creating a new file.

FileStream fs = new FileStream
    (
        "TestFile.txt",
        FileMode.Create,
        FileAccess.Write,
        FileShare.Read
    );

Note: The code is spanned across multiple lines for the sake of clarity.

The first parameter to the constructor is the path to the file. In this case the new file will be created in the working directory of the application. A complete path such as C:\Program Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt can also be used. Backslash being the escape sequence starter would need to be escaped in the string. The code would look something like:-

FileStream fs = new FileStream
    (
        "C:\\Program Files\\Maxotek\\Tutorials\\C-Sharp\\Lesson14\\TestFile.txt",
        FileMode.Create,
        FileAccess.Write,
        FileShare.Read
    );

Another way of doing this, is to use the @ character before the string. This prevents any escape sequence character as the backslash itself is taken as a normal character.

FileStream fs = new FileStream
    (
        @"C:\Program Files\Maxotek\Tutorials\C-Sharp\Lesson14\TestFile.txt",
        FileMode.Create,
        FileAccess.Write,
        FileShare.Read
    );

The second parameter to the constructor is the FileMode enumeration. It can have any of the following values.

File Mode Description
Create Creates a new file or truncates the existing file.
CreateNew Creates a new file. If the file already exists, throws a System.IO.IOException.
Open Opens an existing file. Throws a System.IO.FileNotFoundException if the file does not exist.
OpenOrCreate Opens an existing file or creates a new one. The difference between this mode and the Create mode is that it does not truncate the file.
Append Opens the file and seeks to the end. A new file is created if the file does not exist.
Truncate Opens an existing file and truncates its content so that the file size becomes zero. Attempting to read in this mode throws an exception.

The third parameter is the FileAccess which specifies whether the file is to be opened for Reading (FileAccess.Read), Writing (FileAccess.Write) or both (FileAccess.ReadWrite).

The last parameter is FileShare mode which states how the file will be shared.

FileShare Mode Description
Read Allows other handles to read from the file.
Write Allows other handles to write to the file.
Delete Allows subsequent deleting of the file.
Inheritable Makes the file handle inheritable to child processes.
None Declines sharing of file. No other process can open the file until it is closed.

Note: The constructor is overloaded into many other forms which take various other types and combinations of parameters. The above form was one of the basic ones.

Writing to the File

We use the StreamWriter class which is inherited from the abstract class TextWriter to write a series of characters. After opening the file in the appropriate mode (Write or ReadWrite in this case), a new object of the StreamWriter class is created. The object of the FileStream class is passed to it, thus associating the stream with the file. After this, the content can be written to the file by using the Write or the WriteLine method. WriteLine appends an end of line to the content. These two methods are highly overloaded to enable almost all built in data types to be directly written.

Once you have done all the writing, make sure you close the file using the Close method. This ensures all the content is physically written to the file. For performance reasons, the write operation is buffered and sometimes the content might not be physically written to the file even after the Write method was called. To force all the buffers to be cleared and all buffered content to be written to the underlying stream (File in our case), use the Flush method.

1
2
3
4
5
6
7
8
9
10
11
12
FileStream fs = new FileStream
    (
        "TestFile.txt",
        FileMode.Create,
        FileAccess.Write,
        FileShare.Read
    );
StreamWriter sw = new StreamWriter(fs);
sw.Write("Hello World");
 
sw.Close();     // Close the Stream
fs.Close();     // Close the File

Reading from a fie

The StreamReader class is used to read a series of characters from a FilStream. This class is derived from the abstract class TextReader. Before reading, the file must be opened in the appropriate mode (Read or ReadWrite). To Read the next character or the next set of characters, use the Read method. This method has two forms. One that does not take any parameters and reads the next character. It returns the byte value of the character. The other one takes three parameters:-

  • An array of characters – The read characters are stored in the variable passed here.
  • The index of the buffer at which to begin writing
  • Maximum number of characters to read

The ReadLine method reads a line of characters and returns the result in the form of a string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FileStream fs = new FileStream
    (
        "TestFile.txt",
        FileMode.Open,
        FileAccess.Read,
        FileShare.Read
    );
 
StreamReader sr = new StreamReader(fs);
string str = sr.ReadLine();
while (str != null)
{
    Console.WriteLine(str);
    str = sr.ReadLine();
}
 
sr.Close();     // Close the Stream
fs.Close();     // Close the File

The file pointer can be seeked to any position of the file using the BaseStream property’s Seek method. This method takes two parameters. The first, a byte offset relative to the Origin (second) parameter. This value can be either positive which moves the pointer down the file or negative which moves the file pointer upwards. The second parameter known as the Origin parameter indicates the reference point to obtain the new position. The permissible values are Begin, Current and End.

The following line of code moves the file pointer to the 5th character from the beginning.

sr.BaseStream.Seek(5, SeekOrigin.Begin);

Moves the pointer to the start.

sr.BaseStream.Seek(0, SeekOrigin.Begin);

Moves the pointer to 5 characters ahead of the current position.

sr.BaseStream.Seek(5, SeekOrigin.Current);

Moves the pointer 5 characters backward from the current position.

sr.BaseStream.Seek(-5, SeekOrigin.Begin);

Moves the pointer to the end.

sr.BaseStream.Seek(0, SeekOrigin.End);

The Peek method is used to read the next character without consuming it, i.e the file pointer does not move ahead.

Implementing Binary Read & Write

The StreamReader and StreamWriter classes work with character data. In this mode everything is written as plain text. To implement binary operations, wherein a number such as 327.68 would be written as a float value consuming four bytes and not just as plain text, we need to use the BinaryReader and BinaryWriter classes.

They are very similar to their text counterparts except that no Line (ReadLine and WriteLine) methods are provided. The BinaryReader class also supports data type specific methods such as ReadInt32, ReadDouble, etc. These allow you to directly read the content from the file in the appropriate format. If we were to use the StreamReader class, we would have to convert the string to integer or double format using the Convert.ToInt32 and Convert.ToDouble methods.

Writing to File

1
2
3
int MyNumber = 69;
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(MyNumber);

Reading from file

1
2
BinaryReader br = new BinaryReader(fs);
int MyNumber = br.ReadInt32();
Implementing the Windows File System

Often we need to browse directories and locate files. Many such operations can be accomplished by using the two classes – DirectoryInfo and FileInfo. Both of these are derived from the FileSystemInfo class.

The tables below list some of the commonly used properties and methods corresponding to both of these classes.

Properties of DirectoryInfo Class

Property Description
Attributes Gets or sets attributes associated with the current directory.
CreationTime Gets or sets the Creation time of the directory.
Exists Gets a Boolean value indicating whether the directory exists
FullName Gets a string containing the full path of the directory.
LastAccessTime Gets the last accessed time of the directory.
Name Gets a string containing the name of the directory.

Methods of DirectoryInfo Class

Method Description
Create Creates a directory.
Delete Deletes a directory.
GetDirectories Returns the directories in the current directory. Supports filtering and recursive listing.
GetFiles Returns the file in the current directory.

Properties of FileInfo class

Property Description
Attributes Gets or sets the attributes associated with the current file.
CreationTime Gets or sets the CreationTime of the file.
Directory Gets an instance of the directory to which the file belongs to.
Exists Gets a Boolean value indicating whether the file exists.
Extension Gets a string containing the extension of the file.
FullName Gets a string containing the full path to the file.
LastAccessTime Gets the last access time of the file.
LastWriteTime Gets the time of the last wriiten activity on the file.
Length Gets the length of the file in Bytes.
Name Gets the name of the File.

Methods of FileInfo class

Method Description
Create Creates a new file.
AppendText Appends a text to the file.
Delete Deletes the file.
Open Opens the file.
OpenRead Opens a file in the read-only mode.
Creating Objects

Creating a DirectoryInfo or FileInfo object is very simple. The constructor takes the path to the file.

DirectoryInfo di = new DirectoryInfo("C:\\Windows");
FileInfo fi = new FileInfo("C:\\Windows\\Notepad.exe");
Listing All Files in a Directory

The following code snippet lists all the files in the C:\Windows directory.

1
2
3
4
5
6
DirectoryInfo di = new DirectoryInfo("C:\\Windows");
FileInfo[] fis = di.GetFiles();
foreach (FileInfo fi in fis)
{
    Console.WriteLine(fi.Name);
}

partho C#

C# Tutorial : Lesson 13 – Inheritance – Part II

October 14th, 2007
Abstract Class

Consider the term Vehicle. It does not have an existence of its own. However, types of vehicles; namely, Car, Aeroplane, Bus, etc do. Similarly, we can have Abstract classes which cannot be instantiated thus exhibiting the abstract behavior. They merely contain the skeleton of the class but not its implementation. The abstract keyword is used to declare such a class.

1
2
3
4
5
6
7
8
9
10
abstract class Vehicle
{
 
}
 
static void Main(string[] args)
{
    // Abstract Class cannot be instantiated
    Vehicle obj = new Vehicle();    // Shows Compilation Error.
}
Abstract Methods

Abstract methods contain the function signature and return type, but no body. A child class can override the abstract method thus providing its implementation. Abstract methods are also declared by using the abstract keyword.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
abstract class Vehicle
{
    public abstract void Run();
}
 
class Car : Vehicle
{
    public override void Run()
    {
        Console.WriteLine("Run the Car");
    }
}
 
class Bus : Vehicle
{
    public override void Run()
    {
        Console.WriteLine("Run the Bus");
    }
}

In this example, the abstract method Run() is declared in the Vehicle class. Notice the lack of the { } braces which marks the lack of a body. Since the Vehicle class cannot be instantiated, it does not need to have an implementation for the Run() method. The actual implementation is contained in its derived classes – Car, Bus. Thus, the abstract class only forms the skeleton of the child classes which exhibit specialization by overriding and implementing the abstract methods.

Note: Abstract methods can only be defined inside an abstract class.

Overriding Methods

In the previous example the override keyword is used. A parent class method can be overridden by a child class. In this way it provides its own implementation shadowing the one of the base class. A method must be declared as abstract or virtual to be overridden inside the child class.

Virtual Functions

The difference between a virtual function/method and an abstract method is that while the latter does not provide an implementation, the former does. If a virtual function of the parent class is not overridden, the method is inherited as it is, inside the child class. Again, we use the virtual keyword for declaring virtual functions.

The following example shows various cases when a method can/cannot be overridden.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
abstract class Vehicle
{
    // Abstract Method. Contains no body.
    public abstract void Run();
}
 
class Car : Vehicle
{
    // Abstract method is overridden.
    public override void Run()
    {
        Console.WriteLine("Run the Car");
    }
 
    // Normal Method. Cannot be overridden.
    public void Brake()
    {
        Console.WriteLine("Stop the Car");
    }
 
    // Virtual Method. Can be overridden.
    public virtual void Accelerate()
    {
        Console.WriteLine("Step on the gas");
    }
}
 
class BMW : Car
{
    // An overridden method can be further overridden.
    public override void Run()
    {
        Console.WriteLine("Run the BMW");
    }
 
    // Shows Compilation Error.
    // The Brake method of Car is
    // not declared as virtual or abstract.
    public override void Brake()
    {
        Console.WriteLine("Stop the Car");
    }
 
    // Virtual method is overridden.
    public override void Accelerate()
    {
        Console.WriteLine("Step on the gas");
    }
}

From the following you can deduce that for a method to be overridden, it must be declared as abstract or virtual. An overridden method can be further overridden because it carries over the virtual modifier.

Sealed Classes

So many ways to modify a class but none to protect? Fear not, sealed classes are here to the rescue. This modifier prevents a class from being tampered by not allowing other classes to inherit from it.

1
2
3
4
5
6
7
8
9
10
sealed class Ferari
{
 
}
 
// Shows Error. Cannot inherit from sealed class.
class McLaren : Ferari
{
 
}
Sealed Methods

Use the sealed modifier to prevent a method from being overridden. Normally, you do not need to use this modifier as the methods are not overridable by default. However, if you want to protect an overridden method from being further overridden, you should use the sealed method instead of sealing off the entire class.

Interfaces

Remember that C# does not support multiple inheritance? Multiple inheritance tends to cause more problems than it solves. However, the ability to derive methods and properties from multiple sources is present in C#. This is done using Interfaces. Interfaces only contain the declaration part of a class. The actual definition which comprises of the body of the method is present inside the class which implements the interface.

Declaring Interfaces

They are declared similar to how classes are. Only differences are that they can only contain methods and properties (no variables), they do not contain the definition for these methods/properties and off-course the interface keyword.

interface Flyer
{
	public void Fly();
}
Implementing Interfaces

Classes do not inherit from interfaces, rather implement them. Although, the process of doing this is the same.

class Aeroplane : Flyer
{
 
}

Multiple interfaces can be implemented as follows:-

class Aeroplane : Flyer, Vehicle
{
 
}

Here, Vehicle is also assumed to be an interface.

A class can inherit from another class and implement an interface in a similar fashion:-

class Bird : Mammal, Flyer
{
 
}

Note: Mammal is a class here.

Inheriting Interfaces

Interfaces themselves can inherit from other interfaces. Again, the process is the same.

interface MechanicalFlyer : Flyer
{
 
}
Why use interfaces?

Interfaces provide the skeletal structure of the classes which implement them. They separate the definition of objects from their implementation.

Why not just use Abstract classes?

Abstract classes are meant to be used when you want only some of the methods/properties to be implemented by the sub class. Besides, a class cannot inherit from multiple classes but it can implement multiple interfaces.

The following example depicts the need for interfaces.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
abstract class Animal
{
	public void Eat()
	{
	}
}
 
abstract class Vehicle
{
	public void Run()
	{
	}
}
 
interface Flyer
{
	public void Fly();
}
 
class Aeroplane : Vehicle, Flyer
{
 
}
 
class Bird : Animal, Flyer
{
 
}

As you can see, the two sub classes Bird and Aeroplane derive from the Animal and Vehicle classes respectively. Both have the characteristics of their respective base classes. The Bird like any other animal, eats while the Aeroplane being a vehicle, runs. However, they both share a common trait – the ability to fly. This ability is neither possessed by all animals nor by all vehicles. So it cannot be defined in either of the base classes. Again, it is not only possessed by the Aeroplane and Bird, some insects, baloons and other types of vehicles such as the Helicopter also possess it. It wouldn’t be effective to define this ability in each of them. Actually, it will be defined individually in each of these classes because each have their own way of flying, the bird flaps the wings, whereas the helicopter roatates its through a mechanical engine. However, this ability is declared in the Flyer interface so that any class which implements this interface would have to define the Fly() method by overriding it.

partho C#

C# Tutorial : Lesson 12 – Inheritance – Part I

August 24th, 2007

One of the important aspects of the Object Oriented Methodology is relationship. Objects do not exist as isolated entities, rather, they exhibit some kind of relationship with other objects. Some of the common relationships between the classes are listed below:-

Instantiation Relationship

This is the relationship that exists between a class and its instance or object. Real world examples of such a relationship can be:-

  • A Ferari is a Car
  • A Mobile Phone is a type of electronic device
1
2
3
4
5
6
7
8
9
10
11
class Car
{
	string Model;
	string Company;
	string SerialNumber;
}
 
void Main(string[] args)
{
	Car MyCar = new Car();	// Instantiation Relationship between MyCar & Car
}
Composition Relationship

Classes can be nested i.e a Class can contain another class. The relationship between two such classes is called composition relationship.

Composition

The following code represents the Composition relationship that is depicted in the above diagram.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Car
{
    string SerialNumber;
    string Model;
    string Color;
 
    class Engine
    {
        string Type;
        string Model;
    }
 
    class Wheel
    {
        int Width;
        string Manufacturer;
    }
}
Utilization Relationship

The concept of OOP allows a class to make use of another class i.e delegate some portion of its work to another specialized class. The relationship between these two classes is termed as utilization. Ferari an object of the car class, is driven by Michael, an object of the driver class. These two entities have a utilization relationship between them.

The following code snippet demonstrates the utilization relationship between the Sorter and the Swapper class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Sorter
{
    public static void Sort(int[] A)
    {
        for (int I = 0; I < A.Length - 1; I++)
        {
            for (int J = I + 1; J < A.Length; J++)
            {
                if (A[I] > A[J])
                {
                    // Utilizes the Swapper Class to do the swapping
                    Swapper.Swap(A[I], A[J]);
                }
            }
        }
    }
}
 
class Swapper
{
    public static void Swap(ref int Num1, ref int Num2)
    {
        int Temp = Num1;
        Num1 = Num2;
        Num2 = Temp;
    }
}

This example uses the bubble sort algorithm to sort an array of integers in the ascending order. While sorting, two elements of the list need to be swapped when they are not arranged ascendingly. The Sorter class employs the Swapper class for this job thus utilizing it.

Inheritance

Just as a child inherits qualities from his/her parents, a class can inherit data members and functions from another class. Consider the following class diagram:-

The Mammals class is the base class as it inherits its attributes to other classes. Dogs, cats & Humans are its child classes. This hierarchy is derived from the common set of attributes that the classes share. Mammals, for example are warm blooded, vertebrates, possess external ears and have hair on their body. These characteristics also pertain to Dogs, Cats, Humans, Lions, Tigers and Leopards, thus making them mammals. In C#, a class can have multiple child classes but only 1 base class. Multiple inheritance which existed in languages such as C++ has been scrapped because they tend to cause more problems than they solve.

Some key terms related to Inheritance are listed below.

  • Base(Super) Class – The class that inherits its properties to other classes.
  • Child(Sub) Class – The class that inherits its properties from other classes.
  • Multi-level Inheritance – A class which inherits from another class, serves as the base class for a third class. In the preeceding diagram, Lions, Tigers & Leopards are derived from the Cats class which itself is derived from the Mammals class. This is called multi-level inheritance.
  • Generalization – Classes that inherit from the same base class have certain common attributes which have been inherited from the common base class. This relationship is called Generalization.
  • Specialization – It refers to the uncommon characteristics of a sub class, those that make it different from others. When we say that Human is a kind of Mammal, we imply that they have the common properties of Mammals along with some specialized characteristics that make them different from other Mammals – They walk on two legs. Specialization is the opposite of Generalization.
Implementing Inheritance


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Cars MyFerari = new Cars();
            MyFerari.NumberOfWheels = 4;
            MyFerari.Drive();
        }
    }
 
    public class Vehicles
    {
        private string Name;
        public int NumberOfWheels;
        public void Drive()
        {
        }
    }
 
    public class Cars : Vehicles
    {
 
    }
}

In this example, the Cars class is a sub class which is derived from the Vehicles class. The Cars class inherits the data member NumberOfWheels and the member function – Drive() from the Vehicles class. So, the MyFerari object of the Car class has access to these members.

Note: Private members are not accessible from the sub class. So, the follwoing code would cause a ‘ConsoleApplication1.Vehicles.Name’ is inaccessible due to its protection level. error.

MyFerari.Name = "Ferari";
Determining Inheritance Hierarchies

This process is very simple as the only thing one needs to remember is that the sub class should be a type of the base class. For example: Human is a type of Mammal, Car is a type of vehicle and so on.

Note: Improper usage of Inheritance will not result in any syntactical error. But, the design model for the program would be at fault.

Constructor Inovking Order

Constructors being unique to a class are not inherited. Whenever an object of a child class is created, the constructor of both the parent and the child class is invoked. The parent class must come into existence before its child class can. Therefore, the constructor of the base class is invoked first followed by the constructor of the derived class. The destructors are invoked in the opposite order – derived to base. This is because the child class must be destroyed before the parent class.

The following program confirms these two order.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Cars MyFerari = new Cars();
            Console.ReadLine();
        }
    }
 
    public class Vehicles
    {
        public Vehicles()
        {
            Console.WriteLine("Vehicles -> Constructor Invoked");
        }
 
        ~Vehicles()
        {
            Console.WriteLine("Vehicles -> Destructor Invoked");
        }
    }
 
    public class Cars : Vehicles
    {
        public Cars()
        {
            Console.WriteLine("Cars -> Constructor Invoked");
        }
 
        ~Cars()
        {
            Console.WriteLine("Cars -> Destructor Invoked");
        }
    }
}

partho C#

C# Tutorial : Lesson 11 – Polymorphism – Part II

August 11th, 2007
Operator Overloading

By default, out of the various C# operators, only the dot operator can be applied to user-defined types. Consider the following code snippet:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
 
        Car Car3 = Car1 + Car2;
    }
}
 
class Car
{
    public int Speed;
    public string Name;
}

The compiler generates an error at line 8 saying that the operator + cannot be applied to objects of the Car class. How is the compiler supposed to know whether we want to add the speeds of two cars or concatenate their names. This is where the concept of Operator Overloading jumps in. Before we see how the + operator is prepared to work with the objects of the Car class, we need to understand how the concept works. Given below is a code snippet which accomplishes the addition in objects using a specialized method – Add().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Speed = 30;
        Car2.Speed = 70;
 
        Car Car3 = Car.Add(Car1, Car2);
        Console.WriteLine("Car3's Speed = {0}", Car3.Speed);
        Console.Read();
    }
}
 
class Car
{
    public int Speed;
    public string Name;
 
    public static Car Add(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Speed = Car1.Speed + Car2.Speed;
        return NewCar;
    }
}

The Add method is declared as static so it can be invoked at the class level as Car.Add(). It takes two parameters of the type Car as inputs. It then creates a new object of the Car class, with a speed equal to the sum of the speeds of the input objects – Car1 and Car2. Finally, the new object is returned. In this way, the addition of two objects can be accomplished. The same concept is used in Operator Overloading, except for the fact that the specialized function in their case are of the format operator <operator name>.

Note: The logic inside the Add function is totally up to the the programmer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Speed = 30;
        Car2.Speed = 70;
 
        Car Car3 = Car1 + Car2;
        Console.WriteLine("Car3's Speed = {0}", Car3.Speed);
        Console.Read();
    }
}
 
class Car
{
    public int Speed;
    public string Name;
 
    public static Car operator +(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Speed = Car1.Speed + Car2.Speed;
        return NewCar;
    }
}

As you can see, the + operator utilizes a function in the background to do its neat work. Although the concept in both the cases is same, using operators allows much greater ease. The code Car Car3 = Car1 + Car2; is much closer to the real world and its easier to type, isn’t it?

Here’s a table showing which operators can/cannot be overloaded in C#.

Operators Description
+ – ! ~ ++ – These being unary operators take one operand and can be overloaded.
+ – * / % Binary arithmetic operators take two operands and can be overloaded.
== != < > <= >= Comparison operators take two parameters and can also be overloaded.
&& || These need to be overloaded indirectly using the & and |
+= -= *= /= %= Arithmetic assignment operators cannot be overloaded.
= . ?: -> new is sizeof typeof These special operators cannot be overloaded.

Note: The overloading methods must be declared as public and static.

Overloading Prefix Unary Operators

Below is the logic to accomplish unary – operator overloading. This operator changes the sign of the relative speed and is used as: -<Object Name>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car1.RelativeSpeed = 30;
        Car Car2 = -Car1;
    }
}
 
class Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator -(Car CarObj)
    {
        Car NewCar = new Car();
        NewCar.RelativeSpeed = -CarObj.RelativeSpeed;
        return NewCar;
    }
}

Notice, that the overloaded function takes only a single parameter. If another parameter was specified, this function would overload the binary – operator. Structures being user-defined data types can also be overloaded in this fashion. The only difference is that structures being value types, can be implemented in an easier way.

1
2
3
4
5
6
7
8
9
10
11
struct Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator -(Car CarObj)
    {
        CarObj.RelativeSpeed = -CarObj.RelativeSpeed;
        return CarObj;
    }
}

If the same implementation of the Operator – function was used in a class, both Car1 and Car2 would have the same RelativeSpeed of -30 after line 9. So, in the class implementation we have created a new object of the Car class.

Overloading Pre & Post Increment Operators

Unlike, C++, C# handles the Pre & Post Increment Operators by itself. Hence, we don’t need to overload them separately. Below is the implementation of the ++ operator in the Car structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car1.RelativeSpeed = 30;
        Car Car2 = Car1++;
        Car Car3 = ++Car1;
        Console.WriteLine("Relative speed of Car1 = {0}, Car2 = {1} and Car3 = {2}"
        , Car1.RelativeSpeed, Car2.RelativeSpeed, Car3.RelativeSpeed);
        Console.Read();
    }
}
 
struct Car
{
    public int RelativeSpeed;
    public string Name;
 
    public static Car operator ++(Car CarObj)
    {
        CarObj.RelativeSpeed++;;
        return CarObj;
    }
}

At line 9, the overloaded function for the object Car1 is invoked. The operation being post increment, Car2 gets assigned the current value of Car1 which has a relative speed of 30. After this the RelativeSpeed is incremented by 1. So, Car1 has a relative speed of 31 now. In the next line, pre increment results in the value of Car1 to be incremented by 1 before the value is assigned to Car3. Car1’s RelativeSpeed is now equal to 32. This value gets copied in Car3. So, the output of the code is: Relative speed of Car1 = 32, Car2 = 30 and Car3 = 32.

If the same logic was used in the Car Class’s overloaded function, the output would be: Relative speed of Car1 = 32, Car2 = 32 and Car3 = 32. Why does this happen? As mentioned before, the class is a reference type. Hence, when we say Car1 = Car2, it implies that Car1 now points to the same object in the memory as does Car2. In structures, the same statement would be equivalent to Copy the value of Car2 in Car1.

Arithmetic Assignment Operators

Recall that, the Arithmetic Assignment operators ( += -= *= /= %= ) cannot be overloaded. This is because A += B is equivalent to A = A + B, A -= B is equivalent to A = A – B and so on. Once, you overload the binary + operator, you can perform the += operation on the objects of the class. Same is true for the rest of the Arithmetic operators.

Logical Operators

Overloading Logical Operators is a bit tricky. Firstly, to overload the && operator the function name should be operator & and for || operator it should be operator |. Secondly, before performing these boolean short-circuit operations, the true and false operators need to be defined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
 
class Program
{
    static void Main(string[] args)
    {
        Car Car1 = new Car();
        Car Car2 = new Car();
        Car1.Running = true;
        Car2.Running = false;
 
        Car Car3 = Car1 && Car2;
        Console.WriteLine(Car3.Running);
        Console.Read();
    }
}
 
class Car
{
    public bool Running;
 
    public static Car operator &(Car Car1, Car Car2)
    {
        Car NewCar = new Car();
        NewCar.Running = Car1.Running && Car2.Running;
        return NewCar;
    }
 
    public static bool operator true(Car CarObj)
    {
        return true;
    }
 
    public static bool operator false(Car CarObj)
    {
        return false;
    }
}

partho C#

C# Tutorial : Lesson 10 – Polymorphism – Part I

August 9th, 2007

The term polymorphism means multiple forms. In the world of programming, it refers to the ability of an object to exist in multiple forms. Polymorphism is one one of the key concepts of Object Oriented Programming.

Why do we need polymorphism?

Polymorphism is there to increase the complexity of the already complex world of programming. Just kidding! By using functions, we break down the program into smaller logical parts that are easier to understand, implement and thereby maintain. In this sense, the function is the smallest self sufficient (ideally) logical block of a program. As you get to know more about the real world programming, you’ll find that even these small logical blocks are often very big and rather complex. Consider the following function which is used to calculate the area of a circle from the radius entered as integer.

1
2
3
4
5
double CalcArea(int Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}

This function can only handle integers as input. What if the Radius was in double? The function would fail in such a case. We can create another function named CalcAreaDouble to handle the input in double.

1
2
3
4
5
double CalcAreaDouble(double Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}

While, this works, there’s something wrong about this method. The name of a function should describe(in brief) what it does and not the type of values it returns or takes as input. Both these functions do the same job, Calculate Area. Hence, they should have the same name. Thanks to Polymorphism, we can declare two functions with the same name, inside the same class.

1
2
3
4
5
6
7
8
9
10
11
double CalcArea(int Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}
 
double CalcArea(double Radius)
{
    double Area = Math.PI * Radius * Radius;
    return Area;
}

This is called function overloading. For two functions with the same name to co-exist, they must follow certain rules:-

  • The functions must differ in either the type, the sequence or the number of input parameters i.e they must have different function signatures. The CalcArea functions have different types of parameters.

    These two functions differ in the number of parameters:-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    int SumOfNum(int Num1, int Num2)
    {
        return Num1 + Num2;
    }
     
    int SumOfNum(int Num1, int Num2, int Num3)
    {
        return Num1 + Num2 + Num3;
    }

    While, these have different sequence:-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    float SumOfNum(int Num1, float Num2)
    {
        return Num1 + Num2;
    }
     
    float SumOfNum(float Num1, int Num2)
    {
        return Num1 + Num2;
    }
  • Return type has no influence on function overloading. Hence, these two functions cannot co-exist:-
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    double CalcArea(int Radius)
    {
        double Area = Math.PI * Radius * Radius;
        return Area;
    }
     
    int CalcArea(int Radius)
    {
        double Area = Math.PI * Radius * Radius;
        return Area;
    }
Static Polymorphism

Function overloading along with operator overloading which we shall look at in the next tutorial are ways of implementing static polymorphism. Static polymorphism inturn, is one of the two types of Polymorphism, the other being Dynamic polymorphism. Also called as early binding, this concept refers to an entity existing in different forms. Just like a teacher who carries on the role of a father, a husband, a comrade besides being a teacher, the functions exist in different forms, each specializing in handling one type of role. In static polymorphism, the response to a function is decided at compile time and hence it is also called early binding.

Overloading Constructors

Since constructors are also functions and can be parameterized(takes parameters as input), they can be overloaded. This allows flexibility while creating an object. Consider the Rectangle class declared in the System.Drawing namespace. It can be instantiated by either of the two methods.

Method 1: Using default constructor

In this method, the bounds of the rectangle object Rect are individually set.

1
2
3
4
5
Rectangle Rect = new Rectangle();
Rect.X = 10;
Rect.Y = 20;
Rect.Width = 30;
Rect.Height = 40;

Method 2: Using the Parametrized Constructor

Rectangle Rect = new Rectangle(10, 20, 30, 40);

Notice, how much easier this method is. The initialization in this case is handled by the constructor of the Rectangle class.

The rectangle class would have an implementation similar to this one:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Rectangle
{
    public int X;
    public int Y;
    public int Width;
    public int Height;
 
    Rectangle()
    {
        this.X = 0;
        this.Y = 0;
        this.Width = 0;
        this.Height = 0;
    }
 
    Rectangle(int x, int y, int width, int height)
    {
        this.X = x;
        this.Y = y;
        this.Width = width;
        this.Height = height;
    }
}

As you can see, the class has two overloaded constructors, one being the default constructor which takes no parameter and initializes the values of X, Y, Width and Height to 0. The other one initializes these values based on the inputs to it.

Note: This code is just to give you an idea of how the constructors are implemented. In actual fact, the rectangle class would be a lot more complex than this and would require further codes inside the constructors.

partho C#

C# Tutorial : Lesson 09 – Constructors & Destructors

August 6th, 2007
The need for Initialization

A class contains data members (variables) and member functions. Initializing the values of these data members is essential, at times. Take a look at the following scenarios:-

1
2
int MyNumber;
Console.WriteLine("My Number = {0}", MyNumber);

This block of code declares a variable MyNumber and then prints it on the screen. However, when you try to execute these instructions, an error Use of unassigned local variable ‘Product’ will be generated. This is because, we are trying to use the value of MyNumber, even before we have assigned it one. This is where initialization comes in. Many languages do implicit initialization based on the type of these atomic (int, char, bool, string, etc) data types. Example: 0 for int, false for bool, “” or NULL string for string. But, a strongly typed language like C# doesn’t. The corrected code would be as follows:-

1
2
int MyNumber = 10;
Console.WriteLine("My Number = {0}", MyNumber);

Take a look at this code snippet.

1
2
3
4
5
6
int Product;
for (int I = 1; I <= 10; I++)
{
    Product *= I;
}
Console.WriteLine("The product of the first 10 natural numbers is {0}", Product);

This block of code is meant to calculate the product of the first 10 natural numbers. For this, we have setup a loop running from 1 to 10 and declared a variable named Product to store the running product. Finally, we display the result using Console.WriteLine. Again, this block of code generates an error on line 4. This is because, we haven’t initialized the value of Product. The expression Product *= I is equivalent to Product = Product * I. When this expression is being evaluated for the first time, the Right Hand Side (RHS) part will be evaluated first. This generates the error because at the moment, Product has no value.

In the previous versions of VB (not VB .NET), the value for Product would have been automatically set to 0. While, this would take care of this error, a logical error would creep in and drive the calculations crazy – the product of first 10 natural numbers = 0. To correct this, Product must be initialized to 1. In situations like these, an initialization is a must. Here’s the corrected code:-

1
2
3
4
5
6
int Product = 1;
for (int I = 1; I <= 10; I++)
{
    Product *= I;
}
Console.WriteLine("The product of the first 10 natural numbers is {0}", Product);
Initializing Data Members

Data members can be initialized in a similar fashion:-

1
2
3
4
class MyClass
{
    int MyNumber = 69;
}

However, its a better approach to have a method do all initializations inside a class.

1
2
3
4
5
6
7
8
9
class MyClass
{
    int MyNumber;
 
    public void Initialize()
    {
        MyNumber = 69;
    }
}

After instantiating the object of this class, the method Initialize would have to be called to set the initial value for MyNumber.

1
2
MyClass ClassA = new MyClass();
ClassA.Initialize();

This approach has a disadvantage too. The Initialize method needs to be called explicitly following the object instantiation. This is where the constructor jumps in. To define it: A Constructor is a special method which bears the same name as that of the class it is in and is used for initializing the data members of the class. Summing up the important properties of the constructor:-

  • A Method having the same name as that of the class it is defined in.
  • It does not return any value. Also, it doesn’t have a return type associated with it, not even void.
  • It is used for initializing the data members.
  • A class can have multiple constructors.
  • It is automatically invoked when the class is instantiated.

Here is how the previous example would look when done with constructors.

1
2
3
4
5
6
7
8
9
class MyClass
{
    int MyNumber;
 
    public MyClass()
    {
        MyNumber = 69;
    }
}

Now, when the class is instantiated, the method MyClass() will be automatically invoked and MyNumber will be assigned the value 69.

Static & Instance Constructors

Constructors can either be associated with a class’s instance (object) or the class itself. Instance constructors are the ones associated with the object and are invoked when an object of the class is instantiated. They can be used to initialize the non static members of the class. The above example was that of an instance constructor.

Static constructors on the other hand, are invoked only once during the execution of the program and can be used to initialize the static variables.

Example:-

1
2
3
4
5
6
7
8
9
public class MyClass
{
	static int MyNumber;
 
	static MyClass()
	{
		MyNumber = 69;
	}
}

A class can have these two constructors existing simultaneously:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public class MyClass
    {
        static int MyNumber;
        int YourNumber;
 
        static MyClass()
        {
            MyNumber = 69;
        }
 
        MyClass()
        {
            YourNumber = 69;
        }
    }

Note: Static constructors can’t be used to initialize non-static variables and Instance constructors can’t be used to initialize static variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public class MyClass
    {
        static int MyNumber;
        int YourNumber;
 
        static MyClass()
        {
            YourNumber = 69;  // Error: YourNumber is not a static member
        }
 
        MyClass()
        {
            MyNumber = 69;  // Error: MyNumber is a static member
        }
    }
Parameterized Constructor

The instance constructors we have seen up until this point are all default constructors. They initialize the variables with hard-coded values and are hence not flexible. We can use parameterized constructors to overcome this problem. Parameterized constructors as the name suggests, take parameters with which they initialize the values of the member variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass ClassA = new MyClass(69);
        }
    }
 
    public class MyClass
    {
        int MyNumber;
 
        public MyClass(int Number)
        {
            this.MyNumber = Number;
        }
    }
}

Multiple, parameters can be supplied by separating each of them with a comma. The this keyword can be used to get a reference to the current instance of a class.

Destructors

That which can be created, can be destroyed. Hence came the destructor which has the same name as that of the class it is in and is prefixed by a tilde (~) symbol. Destructors are automatically invoked when the instance of the class is destroyed. They are ideally used to release any memory occupied by the member objects. The .NET Framework automatically manages the memory for the atomic data types (int, string, char, etc). However, user defined data types are managed using a safe mechanism which does not release the memory occupied by an object unless all references to it are destroyed. This can be done in the class destructor. The following example, instantiates an object of the Socket class (located in the System.Net.Sockets namespace) inside the constructor and closes it inside the destructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    class MyClass
    {
        System.Net.Sockets.Socket Sck;
 
        MyClass()
        {
             Sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
 
        ~MyClass()
        {
            Sck.Close();
        }
    }
Garbage Collection

The .NET Framework isolates the programmers from having to handle memory requirements. Garbage collection is the process of releasing the memory occupied by unused objects. Unlike, C++ there is no delete keyword in C# and objects cannot be explicitly destroyed. This job is automatically carried out by a special program of the .NET Framework known as the Garbage collector(GC). This program periodically scans the application for objects with no references and marks them for deletion. It is the GC which determines when the destructor of an object is invoked. This way, the GC ensures that only unused objects get destroyed.

Finalize() Method

This method allows an Object to attempt to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection.

Source: MSDN

This method is invoked when all of the references to an object are released from the memory. It does nothing by default and needs to be overridden. However, the precise timing of when the Finalize method would be invoked cannot be predicted. The CLR utilizes a system called reference-tracing Garbage collection, where by the GC periodically looks for objects that have no references left. Once such an object is found, the CLR invokes the Finalize method for the object, following which, the memory occupied by the object is released.

Dispose() Method

All classes that implement the IDisposable interface must define the Dispose() method. This method is to be used to perform application-defined tasks associated with freeing, releasing, or resetting unmanaged resources like Database connections, etc. Unlike, the Finalize() method, the Dispose() method is not automatically called and it must be explicitly called when the object is no longer in needed.

Fore more information on the Garbage Collection process, read this article written by Jeffrey Richter.

partho C#

C# Tutorial : Lesson 08 – Functions/Methods

July 24th, 2007

The programming model has gone through many refinements, each change improving upon the model. One of the early changes was the inclusion of Subroutines or Subprograms. As the names suggest, these are fragments of code within a program. They offer the following advantages:-

  • Reduction of code duplication by offering re-usability
  • Simplifying program logic by decomposing the program into smaller blocks
  • Improving readability of the program
Why do we need functions?

Consider the following program:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int JoinDay;
 
            Console.WriteLine("Enter the day of Joining:");
            JoinDay = Convert.ToInt32(Console.ReadLine());
 
            switch (JoinDay)
            {
                case 1:
                    Console.WriteLine("You Joined on a Sunday");
                    break;
 
                case 2:
                    Console.WriteLine("You Joined on a Monday");
                    break;
 
                case 3:
                    Console.WriteLine("You Joined on a Tuesday");
                    break;
 
                case 4:
                    Console.WriteLine("You Joined on a Wednesday");
                    break;
 
                case 5:
                    Console.WriteLine("You Joined on a Thursday");
                    break;
 
                case 6:
                    Console.WriteLine("You Joined on a Friday");
                    break;
 
                case 7:
                    Console.WriteLine("You Joined on a Saturday");
                    break;
            }
 
            int ResigDay;
            Console.WriteLine("Enter the Resignation Date:");
            ResigDay = Convert.ToInt32(Console.ReadLine());
 
            switch (ResigDay)
            {
                case 1:
                    Console.WriteLine("You Resigned on a Sunday");
                    break;
 
                case 2:
                    Console.WriteLine("You Resigned on a Monday");
                    break;
 
                case 3:
                    Console.WriteLine("You Resigned on a Tuesday");
                    break;
 
                case 4:
                    Console.WriteLine("You Resigned on a Wednesday");
                    break;
 
                case 5:
                    Console.WriteLine("You Resigned on a Thursday");
                    break;
 
                case 6:
                    Console.WriteLine("You Resigned on a Friday");
                    break;
 
                case 7:
                    Console.WriteLine("You Resigned on a Saturday");
                    break;
            }
 
 
            Console.ReadLine();
 
        }
    }
}

This program displays the weekday of joining and resigning based on the day code entered by the user. While, there are no errors in the code, there is a problem – repetition of code. The switch block in the second case (Resignation Day) is more or less the same except for the prefix to the output message being You Resigned on a . Looping is meant to minimize code repetition, but it is not applicable everywhere. In scenarios such as these we should use functions to reduce code repetition. Below is the same program when done by using a function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
using System;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int JoinDay;
 
            Console.WriteLine("Enter the day of Joining:");
            JoinDay = Convert.ToInt32(Console.ReadLine());
 
            Console.WriteLine("You Joined on a {0}", GetDayFromCode(JoinDay));
 
            int ResigDay;
            Console.WriteLine("Enter the Resignation Date:");
            ResigDay = Convert.ToInt32(Console.ReadLine());
 
            Console.WriteLine("You Resigned on a {0}", GetDayFromCode(ResigDay));
 
            Console.ReadLine();
 
        }
 
        public static string GetDayFromCode(int Code)
        {
            switch (Code)
            {
                case 1:
                    return "Sunday";
 
                case 2:
                    return "Monday";
 
                case 3:
                    return "Tuesday";
 
                case 4:
                    return "Wednesday";
 
                case 5:
                    return "Thursday";
 
                case 6:
                    return "Friday";
 
                case 7:
                    return "Saturday";
 
                default:
                    return "";
            }
 
        }
    }
}

We have saved 28 lines by using the function for just 2 cases – Date of Joining & Resigning.

Note: – We haven’t added provision for handling invalid day codes i.e values not belonging to the range 1 – 7.

The terms function and methods are used interchangeably. Functions are composed of statements that are grouped under a name and can be used repeatedly by just calling the function.

Declaration

Before we can use a function, we need to define its properties, what it does and the value that it returns. Any function declaration has two parts – Signature and Body. We will use this function as our example to study the two parts.

1
2
3
4
5
public int SumOfTwoNumbers(int Num1, int Num2)
{
    int Sum = Num1 + Num2;
    return Sum;
}
Function Signature

The function signature is composed of the Return Type, Function Name and the optional Parameters and Access Specifier.

  • Return Type
    The return type determines the type of value that the function will return. It can be any of the atomic data types (int, char, string, bool, float, etc) or the user defined types (enums, objects, structures). A function that does not return any value should have a return type of void.
  • Function Name
    The function name can be anything that follows the naming rules:-

    • The name must begin with a letter or an underscore & can be followed by a sequence of letters (A-Z), digits (0-9) or underscore (_)
    • Special Characters such as ? – * / \ ! @ # $ % ^ ( ) [ ] { } , ; : . cannot be used in the function name.
    • A function name must not be the same as a reserved keyword such as using, public, etc.
    • The name can contain any number of the allowed characters.
    • Functions with the same class cannot have the same name
  • Parameters
    Functions take values as input, process it and return the output. These inputs are in the form of parameters. The parameters themselves are composed of the data type and the parameter name. The data type restricts the values that can be passed to the function (int only allows Integer values, bool allows Boolean values and so on) and the parameter name can be used like a regular variable under the function body. This variable would be initialized with the value that is passed to the function when it is invoked (called). A function can have any number of parameters each of which need to separated by a comma.
Function Body

This is where we define what the function actually does. In our case, the body is composed of the lineint Sum = Num1 + Num2; which does the actual calculation and return Sum which returns the value to the calling function. Every function (except the constructor and destructor) which doesn’t have a return type of void must return a value. The return value must comply with the data type specified in the signature.

Calling/Invoking the function

By calling/invoking the function, we imply using it – which results in the lines of code written inside it being executed. Calling a function is very simple. We do so by the following syntax:-

FunctionName(param1, param2 …);

In our case, it would go something like – SumOfTwoNumbers(6, 9);. This line will pass the execution to the function SumOfTwoNumbers along with the values 6 and 9 which will get copied in the variables Num1 and Num2. After this, the line int Sum = Num1 + Num2; will be executed and the sum of the two numbers will be stored in the variable Sum. Finally, this value will be returned to the calling function, which basically discards this value (as of now). We can store this result as int MySum = SumOfTwoNumbers(6, 9); or display it on screen as follows Console.WriteLine(SumOfTwoNumbers(6, 9));.

Special Cases

A parameter can have two variations – ref and out. When these prefixes are applied to any parameter, its behaviour changes. Normally, the values passed to the function are just copies of the original value and any changes made to this value have no effect on the original value. By using the ref keyword we can force the value to be passed by reference. This creates an alias of the variable which might have a different name but points to the same address in the memory. Thus, changes made to this value reflect in the original value.

The swap function is a trivial example of this difference:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int A = 10, B = 20;
            Console.WriteLine("The value of A = {0} and B = {1}", A, B);
            Swap(A, B);
            Console.WriteLine("The value (after swapping) of A = {0} and B = {1}", A, B);
            Console.ReadLine();
        }
 
        public static void Swap(int A, int B)
        {
            int Temp = A;
            A = B;
            B = Temp;
            Console.WriteLine("The value (during swapping) of A = {0} and B = {1}", A, B);
        }
    }
}

The output of the following program would be:-

The value of A = 10 and B = 20
The value (during swapping) of A = 20 and B = 10
The value (after swapping) of A = 10 and B = 20

As you can see, the changes made to the value of A and B inside the Swap function have no effect on the values of A and B inside the Main function. This is because both pairs of variable belong to their scopes (the Swap function and the Main Function) and are hence separate. However, by using the ref keyword, we can point the variable A inside the Main and Swap function to the same memory location (same holds for the variable B). The variable A inside the Swap function will be called an alias of the variable A inside the Main function. The alias doesn’t need to have the same name either. The alias stores the memory address of the original variable and not its value.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Collections.Generic;
using System.Text;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int A = 10, B = 20;
            Console.WriteLine("The value of A = {0} and B = {1}", A, B);
            Swap(ref A, ref B);
            Console.WriteLine("The value (after swapping) of A = {0} and B = {1}", A, B);
            Console.ReadLine();
        }
 
        public static void Swap(ref int A, ref int B)
        {
            int Temp = A;
            A = B;
            B = Temp;
            Console.WriteLine("The value (during swapping) of A = {0} and B = {1}", A, B);
        }
    }
}

Output:-

The value of A = 10 and B = 20
The value (during swapping) of A = 20 and B = 10
The value (after swapping) of A = 20 and B = 10

By using the ref keyword, we have made the change persistent inside the Main function.

Note: It is necessary to specify the ref keyword during function calling.

A function can take multiple inputs but only return a single value. There might be situations when we need multiple values as output from the function. We can do this by using either the ref or the out keyword. Both of them result in references being passed. The only difference is that the out keyword passes along null values and is hence ideally suited for output purposes.

Note: It is necessary to specify the out keyword during function calling.

partho C#

C# Tutorial : Lesson 07 – Creating Value Types & Reference Types – Part II

July 23rd, 2007
foreach statement

This statement is explicitly used to traverse through arrays. The benefit of using foreach over the normal for statement is that it is not necessary to check the size of the array while using the former.

Syntax:-

foreach(type identifier in expression)
{
statement 1;
statement 2;

}

Suppose we have an array StudentNames containing the name of all the students in a class. We need to display the name of each one of them on screen. First we will see how it can be done using the for loop.

1
2
3
4
5
string[] StudentNames = new string[] {"Peter", "Tony", "Bruce", "Scott", "Clark", "Kenshin"};
for (int I = 0; I < StudentNames.Length; I  )
{
	Console.WriteLine(StudentNames[I]);
}

Now we’ll use the foreach statement to do this.

1
2
3
4
5
string[] StudentNames = new string[] {"Peter", "Tony", "Bruce", "Scott", "Clark", "Kenshin"};
foreach (string StudentName in StudentNames)
{
	Console.WriteLine(StudentName);
}
Param Arrays

Remember the Console.WriteLine method which outputs the result using a string format followed by the additional values as input parameters. For example: Console.WriteLine(”The sum of {0} and {1} is {2}”, Num1, Num2, Num1 Num2); would display The sum of 5 and 6 is 11 for values 5 and 6 for Num1 and Num2 respectively. What is worth noting here, is that WriteLine() can take any number of parameters after the string format. So, something like this would work as well:-

Console.WriteLine("The Prime Numbers -> {0}, {1}, {2}, {3}, {4}", 2, 3, 5, 7, 11);

This is done by the param array data type. Example:-

1
2
3
4
5
6
7
8
9
public static int Sum(params int[] Numbers)
{
	int Sum = 0;
	foreach (int Number in Numbers)
	{
		Sum  = Number;
	}
	return Sum;
}

This is a function to return the sum of any number of numbers. The numbers to be summed are passed as parameters during the function call as: Sum(4, 69, 13, 99);

Note: param array should be the last parameter in the function signature which also means that only one param array can be used in a function. Why is this done? Consider the following function signature: public static int MyFunction(params int[] A, int C). How would we call the function if this were to be allowed? MyFunction(1, 2, 3, 4, 5); How can the compiler determine where the values for the param array A finish? Actually, if a reverse scanning of parameters were to be done, this could be determined. But that would increase useless complexity of having to implement this along with the normal forward scanning of parameters.

Multi Dimensional Arrays

Up until now, we have only worked with Single Dimensional arrays. Now we shall see how the Multi Dimensional arrays are declared, initialized and manipulated. The pictures below show how the Single and Double Dimensional arrays are represented.

Single Dimensional Array

Multi Dimensional Array

While, the Single Dimensional arrays are represented as a single row of elements, Double Dimensional arrays are represented by multiple rows. Similarly, arrays with 3 dimensions would be represented in 3D space along the three axes.

Declaration

Declaration is done by the syntax:-

datatype [ , ] VariableName;

The number of commas ( , ) inside the square brackets [ ] should be one less than the number of dimensions required for the array.

Example Usage:-

int [ , ] Numbers;
Initialization

Initialization is done in a way where each row is treated like a single dimensional array. Example:-

1
2
3
4
5
6
int[,] Numbers = new int[3, 3]
{
	{1, 2, 3},
	{4, 5, 6},
	{7, 8, 9}
};
Assigning Values

Values can be assigned as:-

Numbers[1, 2] = 7;
Array Class

The Array class defined in the System namespace serves as the base class for all the arrays in the Common Language Runtime. It can be used to create, manipulate, search and sort arrays.

Some of the common Properties and methods are summarized below.

Properties

  • IsFixedSize – Returns a boolean value (True / False) indicating whether the array is of Fixed Size or not.
  • IsReadOnly – Returns a boolean value (True / False) indicating whether the array is Read Only or not.
  • Length – Returns a 32-bit integer that represents the total number of elements across all dimensions in the array.
  • Rank – Returns the number of dimensions (also called the Rank) of the array.
Methods
  • BinarySearch – Performs the faster Binary Search algorithm on the array and returns the number if found.
  • Clear – Resets the value of the supplied range of elements in the array to the default values of the datatype:-
    • int – 0
    • bool – false
    • Reference Data Types – Null
  • Copy – Copies a range of elements to another array along with type casting and boxing as required
  • CopTo – Copies all elements to the specified single dimensional array
  • Find – Searches for the given value and returns its first occurrence in the array
  • FindAll – Returns all occurrences of the searched element in the array
  • GetLength – Returns the 32 bit length of the array
  • GetValue – Returns the value of the specified item in the array
  • IndexOf – Searches for the given value and returns the index of the first position its found in
  • Resize – Resizes the array
  • Reverse – Reverses the order of the elements. (Works only on a single dimensional array)
  • SetValue – Sets the value at the specified location of the array
  • Sort – Sorts the elements. (Works only on a single dimensional array)
Collections

An integer array can only store integers. Same goes for any other array type – string, boolean, etc. Collections overcome this limitation of arrays and can store elements of different types as items. This is possible because Collections actually store references and not values. We use the System.Collections namespace to work with collections.

Boxing – No, not the Sport! Boxing is the automatic conversion of value types to reference types allowing them to be stored in collections.
Unboxing – The reverse of the former, conversion of reference type to value type.

Because Collections store references, it is necessary to do the above conversions while storing and retrieving values in Collections.

Array List – Array List is a better alternative to arrays because of the following advantages it offers over arrays. It resides in the System.Collection namespace.

  • Resizing – Arrays cannot be resized natively. So, one has to create a new array and copy the elements of the existing one followed by rearrangement of references for this process. Array List on the other hand work on the concept of Linked List where memory is allocated and deallocated at runtime as and when required.
  • Adding an element – To add an element we need to first create a new array, copy the values before the position where the new element is to be inserted, insert the new element and then insert the remaining elements. Again, a cumbersome process for arrays. Array Lists only need to allocate memory for the new element and resolve the references of the elements on both side of the new element.
  • Deleting an element – All elements after the element to be deleted need to be shifted forward to fill up the vacancy created by the deletion. Array Lists rely on releasing the memory occupied by the element and resolving the references of the elements on both sides.

Common Methods used by the Array List class:-

  • Add – Adds an item at the end of the Array List
  • Clear – Removes all the items from the Array List
  • Insert – Inserts an element into the Array List at the specified position
  • Reverse – Reverses the order of all the elements or a portion of the Array List
  • Remove – Deletes the item at its first occurrence
  • TrimToSize – Sets the maximum capacity to the number of elements currently in the the Array List

Other Classes that the collection namespace provides are:-

  • Queue – A Collection that works on the First-In-First-Out (FIFO) rule. Here, insertion of elements occur at the rear and deletion at the front.
  • Stack – Works on the Last-In-First-Out (LIFO) rule. Both insertion and deletion occur at the top of the stack.
  • Hash Table – It uses unique keys to access/store elements in the collection.

partho C#

C# Tutorial : Lesson 06 – Creating Value Types & Reference Types – Part I

July 23rd, 2007
Value Types & Reference Types

In C#, Variables are either value types or reference types depending on what they store, values or references. By reference we imply that the variable holds the memory address of another location where the actual value is stored. All built in data types – Int, Char, String, Float, Boolean, etc are value types while classes are reference types. The following is a diagrammatic representation of these two types.

In this picture there are two variables Num1 and Num2. Both of these being integer variables store the values directly.

The two variables in this case are actually objects of a car class. As you can see, they do not store the values directly but only a pointer to the memory location where the value is actually stored.

Consider the following code snippet:-

1
2
3
4
5
6
int Num1, Num2;
Num1 = 100;
Num2 = Num1;
Num1 ++;
Console.WriteLine("Num1={0}", Num1);
Console.WriteLine("Num2={0}", Num2);

Here we declare two integer variables, Num1 and Num2. On line 2 we set the value of Num1 to 100 and at line 3, we copy the value of Num1 to Num2. Both Num1 and Num2 now store 100. In the next line, we increment the value of Num1 by 1, thus it stores 101 now. This doesn’t make any change in the value of Num2 as both of them are value types and have a separate storage location in the memory. Finally, we display the numbers and the output comes as:-

Num1=101
Num2=100

Now take a look at this code snippet:-

1
2
3
4
5
6
Car Ferrari, McLaren;
Ferrari = new Car("F2004");
McLaren = Ferrari;
McLaren.Model = "F2002";
Console.WriteLine("Ferrari={0}", Ferrari.Model);
Console.WriteLine("McLaren={0}", McLaren.Model);

Two objects of the Car class are declared. We instantiate Ferrari by using the new keyword, passing the value F2004 to its constructor which sets the Model to F2004. The third line McLaren = Ferrari; copies the value stored by the object Ferrari to McLaren. All classes being reference types, the objects store the memory address of the actual storage location. Hence, by copying Ferrari to McLaren, we are actually copying the memory location. Now both Ferrari & McLaren are pointing to the same physical location in the memory. In the next line, the model for the McLaren is changed to F2002. This doesn’t make any change to the value stored by the McLaren object, i.e the memory address. The change occurs in the storage location pointed to by the McLaren object. Since, Ferrari is pointing to the same memory location this change reflects there as well and the results of the last two lines are:-

Ferrari=F2002
McLaren=F2002

Structures

A structure is a value data type which is used to group related heterogeneous data types. Say you want to store the details of all the employees of your company such as – Name, Post, Salary, Joining Date, etc. In such a scenario we can create a structure named employee which would be composed of these fields. We use the struct keyword to create structures with the following syntax:-

struct StructureName
{
member variable 1
member variable 2

}

Structures are similar to classes in the sense that they contain data members and functions, have access specifiers and need to be instantiated, but they do have notable differences such as:-

  • Structures are value types whereas classes are reference types
  • Structures can not be inherited
  • They cannot have default constructor

Example Usage:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct Employee
{
	public string Name;
	public string Post;
	public int Salary;
	public string JoiningDate;
}
static void Main(string[] args)
{
	Employee Emp1 = new Employee();
	Console.WriteLine("Enter Employee's Name");
	Emp1.Name = Console.ReadLine();
	Console.WriteLine("Enter Employee's Post");
	Emp1.Post = Console.ReadLine();
	Console.WriteLine("Enter Employee's Salary");
	Emp1.Salary = Console.ReadLine();
	Console.WriteLine("Enter Employee's Joining Date");
	Emp1.JoiningDate = Console.ReadLine();
}

Note: Unlike in other languages such as C/C , structures in C# can have member functions.

Enumeration

Enumeration is another value data type that we use to store non generic values such as the name of the day – Sunday, Monday, etc. One may question the need for enumeration considering that we can use the string data type to store the names. But, one could assign just about any value to the day, which we certainly don’t want. We could also use the numbers from 0 – 6 to denote the 7 days. However, that doesn’t clarify whether 0 is for Sunday or Saturday. The enum keyword is used to create an enumerated data type with the following syntax:-

enum EnumDataType { Value1, Value2, and so on }

Example usage:-

1
2
3
4
5
6
enum Month { Jan, Feb, Mar, Apr, May, Jun, Aug, Sep, Oct, Nov, Dec };
static void Main(string[] args)
{
	Month ThisMonth;
	ThisMonth = Month.May;
}

Note:- The values of an enumerated data type are assigned in design time and not at runtime using the Console.Read or Console.ReadLine method.

Arrays

An array is a collection of values of the same data type, grouped under the same name and referred to by their distinct indexes. This is how they are represented in the memory.

Declaration

Syntax:-

datatype[] ArrayName;

  • Where datatype is the type of data that the array will store – int, string, char, etc.
  • [] Specifies the size of the array.
  • ArrayName is the name with which we would be using the array.
  • Example usage:-

    int[] Marks;

    Initialization
    Memory is allocated to the array only when it is instantiated. The instantiation can be done in the following methods. Once initialized a default value is assigned to all of the elements depending on their data type – 0 for int, “” (NULL String) for char or string, etc.

    Syntax:-

    ArrayName = new datatype[size];

    This step can be done along with the declaration.

    datatype[] ArrayName = new datatype[size];

    Example Usage:-

    int[] Marks = new int[10];

    Note: This creates 10 elements starting from 0 to 9

    Assigning values
    Each element of the array can be accessed by specifying their index along with the ArrayName.

    ArrayName[index] = value;

    Example:-

    Marks[5] = 99;

    Values can also be assigned during declaration as follows:-

    datatype[] ArrayName = {value1, value2, value3 and so on};

    Example:-

    int[] Marks = {100, 13, 69, 99};

    Using this process implicitly sets the size for the array. In this case it would be 4. The elements can be accessed by their indexes starting from 0 to 3. Note: In C# Index always starts at 0.

    Using the following is equivalent to using the above line of code.

    int[] Marks = int[4] {100, 13, 69, 99};

    Copying an Array
    You can copy an array just as easily you copy other variables. Example:-

    1
    2
    
    int[] Source = {0, 1 , 2, 3, 4};
    int[]Destination = Source;

    One point to note is that an array being a reference type, both these arrays point to the same location in memory and any change made in either of them would be reflected in the other one as well. To make separate copies of the array, we need to copy each of the elements individually. The code below does just that.

    1
    2
    3
    4
    5
    6
    
    int[] Source = { 0, 1, 2, 3 };
    int[] Destination = new int[Source.Length]; // Set the size of the destination to be the same as that of the source
    for (int I = 0; I < Source.Length; I  )
    {
    	Destination[I] = Source[I];
    }

    This step can be done along with the declaration.

    datatype[] ArrayName = new datatype[size];

    Example Usage:-

    int[] Marks = new int[10];

    Note: This creates 10 elements starting from 0 to 9

    partho C#