Top Banner
1 | Page Learn C The do-it-yours Quasar S. Chun C# self way nawalla See the output for yourself Write the program Get the gist of the concept
57
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Learn C#

1 | P a g e

Learn C#The do-it-yourself way

Quasar S. Chunawalla

C# yourself way

Quasar S. Chunawalla

See the output for yourself

Write the

program

Get the gist of the concept

Page 2: Learn C#

2 | P a g e

Learn C# - do it yourself way... 2008

For all students pursuing the

Computer Science Stream

These notes were compiled by me, while serving NIIT Training

Institute, Mumbai – India as a faculty member. This text would

facilitate the learning process of the students when they learn an

Object-Oriented Programming language like C#. It starts from scratch

and takes you upto the depth required at an undergraduate school. I

appreciate the contribution made by my students – Farzan, Mario,

Swapnil, Geetashree, Swati, Pooja, Shraddha, Chaitali, Snehal,

Sushil, Anand, Sadiq, Rama, Tausif, Ameya and all other students and

colleagues.

Page 3: Learn C#

3 | P a g e

Learn C# - do it yourself way... 2008

Program Listing

Chapter Name Pages

1 Introduction to C#

2 C# Fundamentals

3 Decision Making and Looping Constructs

4 Classes, Objects and Methods

5 Collections in C#

6 Polymorphism, Constructors and

Destructors

7 Inheritance – Our objects’ family tree

8 Advanced C# Language Concepts

9 File Input and Output

10 Threads, Processes, AppDomains and

Multi-threading

11 Exception Handling

12 Assembly and Reflections

Page 4: Learn C#

4 | P a g e

Learn C# - do it yourself way... 2008

Page 5: Learn C#

1 | P a g e

1

Introduction to C#

1.1 Hello World C# Style

using System;

class Greeting

{

public static void Main(string[] args)

{

Console.WriteLine("Hello World");

}

}

Output :

1. Open the Notepad and type

the following

program.

2. Save the file as Hello.cs

3. Go to Visual Studio Command

Prompt from Start->

All Programs - >Visual

Studio 2008 -> Visual

Studio Tools

4. On the command prompt, go

to the directory,

where you saved the

file.

5. Type cs Hello.cs to compile

the program.

6. Type Hello to run the

program.

Page 6: Learn C#

2 | P a g e

Learn C# - do it yourself way... 2008

1.2 Dissecting the Hello World Program

using System;

class Greeting

{

public static void Main(string[] args)

{

Console.WriteLine("Hello World");

}

}

The program starts with the using statement. Wait for a while, till I

tell you what it means. Then, we declare a class called Greeting. All

code in C# must be written inside a class.

Next, we have written Main(). The word Main() indicates this is the

start of the program. This is where the C# system start the

executing(running) the program. Thus, Main() is the entry

point(starting point) of any program. All statements written inside

Main() are executed line by line. The Main() block is started using a

starting curly brace { and terminated using an ending curly brace }.

Whatever you want to write inside Main() must be enclosed within

this pair of curly braces. On the same lines, whatever you write inside

the class, must be enclosed within { ... }.

In the above program, we have written just one command/statement –

Console.WriteLine().This command is used display text on the VDU

screen. Whatever you put inside Console.WriteLine() gets printed on

the screen, when you run the program. In this case, it is Hello World.

Page 7: Learn C#

3 | P a g e

Learn C# - do it yourself way... 2008

1.3 What are Classes and Objects?

C# is an object-oriented programming language. All the C# code you

write will appear in a class.

In early days of programming, programs were designed using

flowcharts and a sort of top-down design. With this type of design, a

large problem was solved step-by-step. Thus, the solution to a

problem was visualised as a series of steps or operations. To arrive at

the solution, you follow the sequence of steps or procedure. This form

of programming is called Procedural Programming.

The new paradigm of programming is Object-Oriented Programming.

In Object-Oriented Programming, to find the solution, we decompose

a large problem in terms of objects.

So, what really are objects. Any real world entity or thing, say for

example a car, a person, a flight, a ticket-booking, an employee, a

college can be an object in C#. To model real world things, in C# we

create objects.

Just like in the real – world, each object has some features or

characteristics that describe the object, our C# objects also have

features that describe the object. For example, every car has some

name, brand, year of manufacture, price, color which describe it. In

C#, to model this concept, C# car object will also have attributes

name, brand, yearOfManufacture, price, color etc. Every car object

will have its own values of these attributes. Consider the following

two car objects –

1.4 Variables and Constants

A computer takes data as input, performs operations on the input, and

produces an output. We would like to store the input data and output

results in computer memory, so that we can retrieve it for later

purposes.

Page 8: Learn C#

4 | P a g e

Learn C# - do it yourself way...

Before you get to know, how this is done, let’s take brief look at how

Computer memory looks. Just li

computer memory is organised as a series of cells. The cells do not

house people, instead they house data.

computer memory like

Suppose we store the n

suppose, we would lik

to do that? How do we

different names. In a si

to the memory location

of this memory locatio

to say, “Give me the co

a..” and I’ll get the out

Thus, one of the ways

memory location is to

location is allowed to c

changed to 3, such a m

word Variable, becaus

On the other hand, at ti

remain fixed or consta

Before you get to know, how this is done, let’s take brief look at how

Computer memory looks. Just like in a street, people live in houses,

computer memory is organised as a series of cells. The cells do not

house people, instead they house data. We can visualise

e the one below :

number 2 in some memory locatio

e to retrieve the contents of this ce

e refer to this cell? The houses in a

imilar fashion, what we do is, we

n, say ‘a’. And then, we can acces

on using the name ‘a’. Next time, I

ontents of the memory location wh

tput = 2.

to access and manipulate the valu

give it a name. If the data stored i

change, for example if value in a c

memory location is called a Variab

se, the contents of such a cell can v

imes, we would like to contents of

ant, not allowing it to change. For e

2008

Before you get to know, how this is done, let’s take brief look at how

ke in a street, people live in houses,

computer memory is organised as a series of cells. The cells do not

the picture of

on. Next time,

ell. Then how

a street have

give a name

ss the contents

I simply have

hose name is

ues(data) of a

in a memory

can be

ble. We use the

vary.

f a cell to

example, if a

Page 9: Learn C#

5 | P a g e

Learn C# - do it yourself way... 2008

stores 3.14 – the value of Pi, we would like it to be fixed. Such a

memory location is called Constant. The name given to a Variable is

called a Variable name. The name given to a constant is called

Constant Name.

In a nutshell, variables and constants provide named access to

memory location.

1.5 Variables Declaration

Page 10: Learn C#

6 | P a g e

Learn C# - do it yourself way... 2008

6

Polymorphism, Constructors

and Destructors

6.1 Function Overloading

class Test

{

public int Multiply(int a, int b)

{

return a * b;

}

public double Multiply(double a, double b)

{

return a * b;

}

public double Multiply(int a, double b)

{

return a * b;

}

public double Multiply(double a, int b)

{

return a * b;

}

public int Multiply(int a, int b, int c)

{

return a * b * c;

}

}

class OverloadDemo

{

public static void Main()

{

Test t = new Test();

double res1 = t.Multiply(4.2, 5.5);

int res2 = t.Multiply(3, 5);

double res3 = t.Multiply(4.2, 5);

There are 6 different versions of the

Multiply() method in the Test class.

The 1st

version multiplies two ints

and returns an int as the answer.

The 2nd

version accepts 2 doubles as

input parameters and returns a

double result as the answer. The 3rd

version accepts an integer and a

double number as an argument, and

returns their product as the answer.

Every time, we are assigning a new

extra meaning to the Multiply()

function. Thus, we have overloaded

the Multiply() method.

Page 11: Learn C#

7 | P a g e

Learn C# - do it yourself way... 2008

double res4 = t.Multiply(5, 3.8);

int res5 = t.Multiply(3, 4, 5);

}

}

In method overloading, we assign a new extra meaning to the method.

For example suppose, we have written the Multiply() method as

follows :

public int Multiply(int x, int y)

{

int result = x * y;

return result;

}

The Multiply() method is designed to accept 2 integers as input

parameters. It multiplies the two integers x and y, and returns an

integer result as the answer.

Suppose, we now define one more Multiply() method as follows -

public double Multiple(double x, double y)

{

double result = x * y;

return result;

}

This Multiply() method multiplies two double numbers and returns a

double result as the answer. Thus, the Multiply() method now has two

different versions. The first version can multiply two integers,

whereas the second version can multiply 2 doubles. Thus, we have

assigned a new extra meaning to the Multiply() method, so that it can

now no longer multiply just two ints, but it can as well multiply two

doubles.Hence, we have overloaded the Multiply() method. Thus, this

is method overloading.

Let us define one more Multiply() method as follows -

Page 12: Learn C#

8 | P a g e

Learn C# - do it yourself way... 2008

public double Multiply(int x, double y){

double result;

result = x * y;

return result;

}

This time round, the Multiply() method can multiply one int with one

double value, and returns a double result as the answer. Thus, we are

again assigning a new extra meaning to the Multiply() method. So,

once again we have overloaded the Multiply() function.

If we define one more Multiply() method as :

public double Multiply(double x, int y)

{

double result;

result = x * y;

return result;

}

This new version of the Multiply() method can now multiply a double

with an integer. Mutiplying a double with an int, is different from

multiplying an int with a double.

Thus, we are again assigining a new meaning to the Multiply()

method. Hence, we have again overloaded the Multiply() method.

Consider another version of the Multiply method -

public int Multiply(int x, int y, int z){

return x * y * z;

}

This version of the Multiply() method computes the product of 3 ints

instead of 2. Once again we have assigned extra meaning to

Multiply(). So, it is an overloaded function.

A function is said to be overloaded if -

Page 13: Learn C#

9 | P a g e

Learn C# - do it yourself way... 2008

1. When two or more methods in the same class have the same name

2. They have different Parameter Lists

Parameter list is different if -

- Type of parameters differs.

- No of parameters is different.

- Order of parameters is different.

6.2 Operator Overloading

class Date

{

public int day;

public int month;

public int year;

public static Date operator +(Date d1, Date d2)

{

Date result = new Date();

result.day = d1.day + d2.day;

result.month = d1.month + d2.month;

result.year = d1.year + d2.year;

if(result.day>30){

result.day -= 30;

result.month++;

}

if (result.month > 12)

{

result.month -= 12;

result.year++;

}

return result;

}

public static bool operator <(Date d1, Date d2)

{

bool ans;

int days1 = d1.day + d1.month * 30 + d1.year *

365;

int days2 = d2.day + d2.month * 30 + d2.year *

365;

if (days1 < days2)

ans = true;

else

ans = false;

return ans;

}

public static bool operator >(Date d1, Date d2)

A Date class is used to represent the

date in the form of days, months

and years.

The + operator is overloaded, so that

it can add two Date class objects.

The two Date objects are passed as

arguments into d1 and d2. To store

the sum of Date objects, we take a

result Date object. We set the day,

month and year of the result Date

object as the sum of the

corresponding day, month and year

of d1 and d2.

We also need to check for overflow.

Overflow happens when the no of

resulting days exceeds 30. For

example, we treat 35 days as 1

month and 5 days. So, when an

overflow occurs we add 1 to the

months, and the balance days are 35

– 30 = 5.

The < operator is overloaded, so that

it can compare 2 Date objects and

find out which is smaller. Comparing

2 Date objects for the no. Of days,

months and years can be tricky, so a

simple way would be to find the

total no of days of each Date object

and then just compare them. If

days1 turns out to be less than

days2 as assumed, return true else

return false. We also overload >

operator, since they must be

overloaded in pairs.

Page 14: Learn C#

10 | P a g e

Learn C# - do it yourself way...

{

bool ans;

int days1 = d1.day + d1.month * 30 + d1.year * 365;

int days2 = d2.day + d2.month * 30 + d2.year * 365;

if (days1 > days2)

ans = true;

else

ans = false;

return ans;

}

public void GetDate()

{

Console.WriteLine(

Console.WriteLine(

Console.WriteLine(

Console.WriteLine();

}

}

class DateDemo

{

public static void Main()

{

Date d1 = new Date

Date d2 = new Date

Date result;

bool ans;

d1.day = 2;

d1.month = 7;

d1.year = 5;

d2.day = 29;

d2.month = 6;

d2.year = 4;

result = d1 + d2;

d1.GetDate();

d2.GetDate();

result.GetDate();

ans = (d1 > d2);

Console.WriteLine(

}

}

Suppose we write the instruction 2 + 3.

days1 = d1.day + d1.month * 30 + d1.year * 365;

days2 = d2.day + d2.month * 30 + d2.year * 365;

(days1 > days2)

;

GetDate()

.WriteLine("Day : " + day);

.WriteLine("Month : " + month);

.WriteLine("Year : " + year);

.WriteLine();

Main()

Date();

Date();

result = d1 + d2;

result.GetDate();

ans = (d1 > d2);

.WriteLine("d1 > d2 : " + ans);

Suppose we write the instruction 2 + 3.

2008

Page 15: Learn C#

11 | P a g e

Learn C# - do it yourself way... 2008

When the C# system encounters this line, it does not directly add the

2 + 3. Instead, the C# system calls a function with the name + and

passes 2 and 3 as the arguments.

+(2,3)

When this function is called, the control jumps to the function

definition. The + function looks like this

public int operator +(int a, int b)

{

___________________;

___________________;

___________________;

}

Since, the computer gives us the answer of 2 + 3 = 5, this function +

is already defined in C#. Now, suppose we would like to assign extra

meaning to the + operator.

Let's say we have the following objects -

MyClass obj1 = new MyClass();

MyClass obj2 = new MyClass();

Suppose, we now write

obj1 + obj2

Thus, the following function is called -

+(obj1,obj2)

But, since these our own objects, we have created them, we have

made their class design, the + operator does not know how to add

these custom made objects. To be able to add them, we need to define

the following function -

Page 16: Learn C#

12 | P a g e

Learn C# - do it yourself way... 2008

public MyClass operator + (MyClass obj1, MyClass obj2){

MyClass result;

//Code for adding the 2 objects..

_______________________________;

_______________________________;

return result;

}

By defining this function, the + operator will also be able to add

objects. Hence, we are assigning extra meaning to the + operator, so

that it is able to add our own objects. Hence, it is called Operator

Overloading.

Syntax for Overloading Binary Arithmetic Operator

public static MyClass operator + (MyClass obj1, MyClass obj2)

{

MyClass result;

______________

______________

return result;

}

Syntax for Overloading Unary Arithmetic Operator

public static MyClass operator -(MyClass obj)

{

MyClass result;

______________

______________

return result;

}

Page 17: Learn C#

13 | P a g e

Learn C# - do it yourself way... 2008

Syntax for Overloading Relational Operators

public static bool operator <(MyClass obj1, MyClass obj2){

bool ans;

//Compare the two objects

______________

______________

return ans;

}

Note : Relational operators are always overloaded in pairs.

If we overload < operator, then we must also overload > operator.

Similarly, if we overload <= or == operator, we must also overload

their corresponding complementary operators >= and !=.

6.3 Constructors

class Box

{

double width;

double height;

double depth;

public Box()

{

width = height = depth = 1;

}

public Box(int l)

{

width = height = depth = l;

}

public Box(int w, int h, int d)

{

width = w;

height = h;

depth = d;

}

public void GetBox()

{

Console.WriteLine("w : " + width + " h : " + height + " d :

"+depth);

}

Page 18: Learn C#

14 | P a g e

Learn C# - do it yourself way...

public void Volume()

{

Console.WriteLine(

}

}

class BoxDemo

{

public static void Main()

{

Box myBox1 = new

Box myBox2 = new

Box myBox3 = new

myBox1.GetBox();

myBox2.GetBox();

myBox3.GetBox();

myBox1.Volume();

myBox2.Volume();

myBox3.Volume();

}

}

A constructor is a special method that is called automatically, when

an object is created.

Why Constructors?

When we first create an object, all its fields are initiali

other words, the memory is zeroed out.

Box myBox;

myBox = new Box();

To be able to use this Box object, we must put in meaningful values in

the width, height and depth of myBox. Thus, we must assign values to

myBox’s instance variables.

To do so, we must manually go in and initialise all the fields of the

myBox object.

Volume()

.WriteLine("Volume : " + width * height * depth);

Main()

new Box();

new Box(5);

new Box(10, 20, 30);

myBox1.GetBox();

myBox2.GetBox();

;

myBox1.Volume();

myBox2.Volume();

myBox3.Volume();

A constructor is a special method that is called automatically, when

Why Constructors?

When we first create an object, all its fields are initialised to 0. In

other words, the memory is zeroed out.

Box myBox;

myBox = new Box();

To be able to use this Box object, we must put in meaningful values in

the width, height and depth of myBox. Thus, we must assign values to

myBox’s instance variables.

To do so, we must manually go in and initialise all the fields of the

2008

ght * depth);

A constructor is a special method that is called automatically, when

sed to 0. In

To be able to use this Box object, we must put in meaningful values in

the width, height and depth of myBox. Thus, we must assign values to

To do so, we must manually go in and initialise all the fields of the

Page 19: Learn C#

15 | P a g e

Learn C# - do it yourself way...

myBox.width = 10;

myBox.height = 20;

myBox.depth = 30;

All of this seems rosy-

object. But, consider a real

keep track of thousands of orders and consignments. Each

consignment is shipped in Box object. So, if we typically have 1000

Box objects; myBox1, myBox2, myBox3,... this process of manually

initialising all the fields becomes very

Well, you can use convenience methods like SetBox(). But, when you

have a thousand objects, you have explicitly call/invoke SetBox()

method on each Box object. Once again, it calls for a lot of work.

How can Constructors hel

myBox.width = 10;

myBox.height = 20;

myBox.depth = 30;

-rosy till we have to work with just 1 Box

object. But, consider a real-time shipping application, where we to

keep track of thousands of orders and consignments. Each

consignment is shipped in Box object. So, if we typically have 1000

Box objects; myBox1, myBox2, myBox3,... this process of manually

initialising all the fields becomes very tedious and cumbersome.

Well, you can use convenience methods like SetBox(). But, when you

have a thousand objects, you have explicitly call/invoke SetBox()

method on each Box object. Once again, it calls for a lot of work.

How can Constructors help me?

2008

rosy till we have to work with just 1 Box

application, where we to

keep track of thousands of orders and consignments. Each

consignment is shipped in Box object. So, if we typically have 1000

Box objects; myBox1, myBox2, myBox3,... this process of manually

tedious and cumbersome.

Well, you can use convenience methods like SetBox(). But, when you

have a thousand objects, you have explicitly call/invoke SetBox()

method on each Box object. Once again, it calls for a lot of work.

Page 20: Learn C#

16 | P a g e

Learn C# - do it yourself way... 2008

Constructor is a special method that is invoked automatically, when

an object is created. So, you don’t have to call a constructor method

explicitly.

Thus, constructor can be used to automatically initialise an object,

right at the time when the object is born/created.

1. A constructor has the same name as the class.

2. Like methods, constructors can also accept input parameters.

3. Unlike methods, constructors do not have a return type, not even

void.

4. Like methods, constructors can also be overloaded. Depending

upon the call, different versions of the constructor will be invoked.

Note – Adding constructors to a class is compulsory.

Q. But, the classes that we have written till now seemed to work fine

without a constructor.

A. If you do not write your own constructor, the C# Compiler adds a

constructor method for you for free. Such a constructor is called the

default constructor.

Q. But how does the default constructor know, what I want it to do?

A. It does not! That’s why, it does not accept any parameters and has

empty body. It looks like this –

public Box()

{

}

Thus, the free constructor that C# compiler adds for you, is a do-

nothing constructor.

Page 21: Learn C#

17 | P a g e

Learn C# - do it yourself way... 2008

6.4 Destructors, Finalize() and

Dispose()

We know that when, objects are created, constructors are called, but

when objects are destroyed what happens?

Unlike C C++, in C# you don’t have to manually destroy objects.

Objects which are no longer needed are automatically destroyed by

the Garbage Collector(GC).

In C#, you can have two kinds of resources in the programs you write.

The Objects of a class, primitive data-types etc. are supported by C#,

and the space occupied by them is automatically release by the GC,

when it finds they are no longer in use. Such resources are called

Managed Resources.

But, there are other resources, like a Database Connection, a File

Stream, a Network Stream, a pipe etc. which are not supported by C#.

This means, when they are no longer in use, the responsibility of their

clean-up does not lie with the GC. You have to make sure, you clean

up these resources. Such resources are called unmanaged resources.

If your program/class uses unmanaged resources, you can clean up

these resources in two ways –

1)Write a destructor or finalizer method.

2)Override the Dispose() method.

If you write a destructor in the class, it is called just before the objects

of this class are destroyed by GC. There are two ways to write a

destructor –

class MyClass

{

~MyClass()

{

Console.WriteLine("You can free up an unmanaged resources here.");

}

}

Page 22: Learn C#

18 | P a g e

Learn C# - do it yourself way... 2008

class DestroyDemo

{

public static void Main()

{

MyClass obj = new MyClass();

obj = null;

}

}

A destructor has the same name as the class, but prefixed with a ~

tilde sign. Internally, this Destructor is translated to a call to the

Finalize() method –

class MyClass

{

protected override void Finalize()

{

try

{

Console.WriteLine("You can free up any unmanaged resources

here");

}

finally

{

base.Finalize();

}

}

}

Now, when you have a number of objects, the order in which these

objects will be destroyed/finalized is not fixed or known. Say, if we

have five objects obj1, obj2, obj3, obj4, obj5 of a class MyClass. The

GC may decide to destroy the objects in any random order say, for

example obj3, obj5,obj1, obj4, obj2. The GC maintains a queue of all

the objects that are to be finalized. This is called Finalization Queue.

In other words, finalization is non-deterministic(random). When we

want to exercise control over the finalization process, we can override

the Dispose() method (whose interface is IDisposable). The Dispose()

method differs from the Finalize() method, in that, we need to

explicitly call the Dispose() method. A finalizer is implicitly called,

and cannot be explicitly called, even if you wanted to.

Implicit Resource Cleanup Destructor or Finalize() method

Explicit Resource Cleanup Dispose()

Page 23: Learn C#

19 | P a g e

Learn C# - do it yourself way... 2008

7

Inheritance – Our objects’

family tree

7.1 Overview of Inheritance

Kathy is assigned the task of building an Employee Management

System. She starts by thinking, “I am gonna take Employee objects

for every Employee” in the organisation. So, she begins by writing an

Employee class as follows –

class Employee

{

public string name;

public string address;

public int SSN;

public int number;

public float salary;

public float computePay()

{

return salary / 12.0F;

}

}

The design of an Employee class seems fine to her initially. An

employee has a name, address, and number and so on... We want the

compute the pay of different Employee objects.

But, Kathy questions herself, does every Employee have a salary? Is it

true that every Employee object has a salary. By studying the problem

Page 24: Learn C#

20 | P a g e

Learn C# - do it yourself way... 2008

domain, she finds out that there are Employees which are paid on an

hourly basis, or employees which are on contract basis.

The first mistake Kathy made was to add a field of type salary to

Employee. She discovers although employees are the objects in our

problem domain, there are actually two different types of Employee

objects : Salaried Employees and Hourly Employees. Therefore, we

should write two classes : Salary and Hourly.

The Salary class should have a field to represent the employee’s

annual salary because a Salaried Employee has a salary. The Hourly

class should have fields to represent the employee’s hourly pay rate

and the no of hours for which he worked.

The Salary and Hourly classes look like this –

class Salary

{

public string name;

public string address;

public int SSN;

public int number;

public int salary;

public float computePay()

{

return salary / 12.0F;

}

}

class Hourly

{

public string name;

public string address;

public int SSN;

public int number;

public int hoursWorked;

public int hourlyRate;

public int computePay()

{

return hoursWorked*hourlyRate;

}

}

Although Salary and Hourly classes are different types, they are not

entirely different. In fact, the two types of employees have a lot in

common, as seen by the repetition of fields and methods in these two

Page 25: Learn C#

21 | P a g e

Learn C# - do it yourself way... 2008

classes. So, we can take the common elements from both the classes,

and put them in a parent class leaving the unique elements behind in

the child class. We can simply make the Salary and Hourly classes

inherit the elements of the Employee class.

Employee class is called Parent class/Base class/Super class.

Salary and Hourly classes are called child class/Derived class/sub-

class.

If you want to make Salary and Hourly the child classes of Employee,

we write them as follows :

class Employee

{

public string name;

public string address;

public int SSN;

public int number;

}

class Salary : Employee

{

public int salary;

public float computePay()

{

return salary / 12.0F;

}

}

class Hourly : Employee

{

public int hoursWorked;

public int hourlyRate;

public int computePay()

{

return hoursWorked*hourlyRate;

}

} When your classes use inheritance, you only need to write your code once.

In the above scenario, Salary class and the Hourly class have a lot of

same code.

Page 26: Learn C#

22 | P a g e

Learn C# - do it yourself way...

Salary Employee and Hourly Employee are both employees.

When you have two classes which are more specific cases of

something more general, you can set them up to inherit from the same

base class.

Build up your class model, by starting General and getting more Specific

7.2 Method Overriding

class Employee

{

public string name;

public string address;

public int SSN;

public int number;

Salary

salary

computePay()

Salary Employee and Hourly Employee are both employees.

When you have two classes which are more specific cases of

something more general, you can set them up to inherit from the same

Build up your class model, by starting General and getting more Specific

7.2 Method Overriding

address;

Employee

name

address

SSN

number

GetEmployee()

Hourly

hourlyRate

hoursWorked

computePay()

2008

Salary Employee and Hourly Employee are both employees.

When you have two classes which are more specific cases of

something more general, you can set them up to inherit from the same

Build up your class model, by starting General and getting more Specific

hoursWorked

computePay()

Page 27: Learn C#

23 | P a g e

Learn C# - do it yourself way... 2008

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine();

}

}

class Salary : Employee

{

public int salary;

public float computePay()

{

return salary / 12.0F;

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine("Salary : " + salary);

Console.WriteLine();

}

}

class Hourly : Employee

{

public int hoursWorked;

public int hourlyRate;

public int computePay()

{

return hoursWorked * hourlyRate;

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine("Hours Worked : " + hoursWorked);

Console.WriteLine("Hourly Rate : " + hourlyRate);

Console.WriteLine();

}

}

class EmployeeDemo

{

public static void Main()

{

Employee e = new Employee();

e.name = "Robert Smith";

e.address = "111 Palm street";

e.SSN = 999901111;

e.number = 1;

Page 28: Learn C#

24 | P a g e

Learn C# - do it yourself way... 2008

Salary s = new Salary();

s.name = "Jane Smith";

s.address = "Oak Drive";

s.SSN = 111009999;

s.number = 2;

s.salary = 10000;

Hourly h = new Hourly();

h.name = "George Washington";

h.address = "333 Espresso Lane";

h.SSN = 111990000;

h.number = 3;

h.hoursWorked = 200;

h.hourlyRate = 30;

e.GetEmployee();

s.GetEmployee();

h.GetEmployee();

}

}

7.3 Use of base keyword

using System;

class Employee

{

public string name;

public string address;

public int SSN;

public int number;

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine();

}

}

class Salary : Employee

{

public int salary;

public float computePay()

{

return salary / 12.0F;

}

public void GetEmployee()

{

base.GetEmployee();

Console.WriteLine("Salary : " + salary);

Console.WriteLine();

}

}

Page 29: Learn C#

25 | P a g e

Learn C# - do it yourself way... 2008

class Hourly : Employee

{

public int hoursWorked;

public int hourlyRate;

public int computePay()

{

return hoursWorked * hourlyRate;

}

public void GetEmployee()

{

base.GetEmployee();

Console.WriteLine("Hours Worked : " + hoursWorked);

Console.WriteLine("Hourly Rate : " + hourlyRate);

Console.WriteLine();

}

}

class EmployeeDemo

{

public static void Main()

{

Employee e = new Employee();

e.name = "Robert Smith";

e.address = "111 Palm street";

e.SSN = 999901111;

e.number = 1;

Salary s = new Salary();

s.name = "Jane Smith";

s.address = "Oak Drive";

s.SSN = 111009999;

s.number = 2;

s.salary = 10000;

Hourly h = new Hourly();

h.name = "George Washington";

h.address = "333 Espresso Lane";

h.SSN = 111990000;

h.number = 3;

h.hoursWorked = 200;

h.hourlyRate = 30;

e.GetEmployee();

s.GetEmployee();

h.GetEmployee();

}

}

7.4 Adding Constructors

using System;

public class Employee

{

public string name;

public string address;

public int SSN;

Page 30: Learn C#

26 | P a g e

Learn C# - do it yourself way... 2008

public int number;

public Employee()

{

Console.WriteLine("Inside Grandparent");

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine();

}

}

public class Salary : Employee

{

public int salary;

public Salary()

{

Console.WriteLine("Inside Parent");

}

public float computePay()

{

return salary / 12.0F;

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine("Salary : " + salary);

Console.WriteLine();

}

}

public class PartTimeSalary : Salary

{

public PartTimeSalary()

{

Console.WriteLine("Inside PartTimeSalary");

}

}

class EmployeeDemo

{

public static void Main()

{

PartTimeSalary pts = new PartTimeSalary();

}

}

7.5 Calling Parent class Constructors

Page 31: Learn C#

27 | P a g e

Learn C# - do it yourself way... 2008

using System;

public class Employee

{

public string name;

public string address;

public int SSN;

public int number;

public Employee(string n, string a, int S, int num)

{

name = n;

address = a;

SSN = S;

number = num;

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine();

}

}

public class Salary : Employee

{

public int salary;

public Salary(string n,string a, int S, int num, int

sal):base(n,a,S,num)

{

salary = sal;

}

public float computePay()

{

return salary / 12.0F;

}

public void GetEmployee()

{

Console.WriteLine("Name : " + name);

Console.WriteLine("Address : " + address);

Console.WriteLine("SSN : " + SSN);

Console.WriteLine("Number : " + number);

Console.WriteLine("Salary : " + salary);

Console.WriteLine();

}

}

class EmployeeDemo

{

public static void Main()

{

Salary s = new Salary("Jane Smith", "222 Oak Drive", 111009999, 3,

10000);

s.GetEmployee();

}

}

Page 32: Learn C#

28 | P a g e

Learn C# - do it yourself way... 2008

8

Advanced C# Language

Concepts

8.1 Using Parent class references to

Child Objects

An object reference can refer to an object of its class, or to an object

of any class derived from it by Inheritance. Suppose, we have the

following class hierarchy.

For example, if Animal class is the parent, and Bird is its child,

SongBird is the child of Bird and so on,... Animal reference can refer

to a Bird object or a SongBird object.

Animal a;

Page 33: Learn C#

29 | P a g e

Learn C# - do it yourself way... 2008

a = new Animal();

a = new Bird();

a = new SongBird();

Assigning an object to an ancestor reference is considered to be a

widening conversion, and can be performed using simple assignment.

Animal a = new MockingBird();

Assigning an ancestor object to a child reference can also be done, but

it is considered to be a narrowing conversion and must be done with a

cast.

MockingBird m = (MockingBird)new Bird();

The widening conversion is the most useful for implementing

polymorphism.

8.2 Polymorphism via Inheritance

A polymorphic reference is the one which can refer to different types

of objects at different times. Such an object reference can refer to one

object at one time, and can refer to another object(related by

inheritance) at another time.

It is the type of object being reference, not the reference type, which

determines which method is invoked. Polymorphic references are

therefore resolved at run-time, not during compilation; hence it is

called dynamic binding.

class Shape

{

public virtual void Area()

{

}

}

Page 34: Learn C#

30 | P a g e

Learn C# - do it yourself way... 2008

class TwoDimShape : Shape

{

public int a;

public int b;

}

class ThreeDimShape : Shape

{

public int a;

public int b;

public int c;

}

class Rectangle : TwoDimShape

{

public override void Area()

{

int area = a * b;

Console.WriteLine("Area : " + area);

}

public void SetRectangle(int x, int y)

{

a = x; b = y;

}

}

class Triangle : TwoDimShape

{

public override void Area()

{

double area = 0.5 * a * b;

Console.WriteLine("Area : " + area);

}

public void SetTriangle(int bas, int height){

a = bas;

b = height;

}

}

class Cube : ThreeDimShape

{

public override void Area()

{

int area = 6 * a * a;

Console.WriteLine("Area : " + area);

}

public void SetCube(int s)

{

a = b = c = s;

}

}

class Box : ThreeDimShape

{

public override void Area()

{

int area = 2 * a * b + 2 * b * c + 2 * a * c;

Console.WriteLine("Area : " + area);

Page 35: Learn C#

31 | P a g e

Learn C# - do it yourself way... 2008

}

public void SetBox(int x, int y, int z)

{

a = x;

b = y;

c = z;

}

}

class ShapeDemo

{

public static void Main()

{

int choice;

Shape s = new Shape();

Triangle t = new Triangle();

t.SetTriangle(5,10);

Rectangle r = new Rectangle();

r.SetRectangle(10,10);

Cube c = new Cube();

c.SetCube(5);

Box b = new Box();

b.SetBox(10,20,30);

while (true)

{

Console.WriteLine("Enter a choice : ");

Console.WriteLine("1 - Rectangle");

Console.WriteLine("2 - Triangle");

Console.WriteLine("3 - Cube");

Console.WriteLine("4 - Box");

Console.WriteLine("5 - Exit");

choice = Convert.ToInt32(Console.ReadLine());

if (choice == 1)

s = r;

if (choice == 2)

s = t;

if (choice == 3)

s = c;

if (choice == 4)

s = b;

if (choice == 5)

break;

s.Area(); //Call is resolved at run-time

}

}

}

Page 36: Learn C#

32 | P a g e

Learn C# - do it yourself way... 2008

8.3 Abstract Classes and Abstract

Methods

Abstraction is the ability to make a class/method/property abstract in

C#. An abstract class is the one which cannot be instantiated. All

other functionalities of the class still exist, its fields, its methods and

constructors are all accessed in the same way. You just cannot create

objects of an abstract class.

An abstract class might initially seem like an odd design. Why write a

class and not allow anyone to create objects of it?

The Employee class that we have written in the previous programs is

an example where we do not want to create objects of Employee.

Notice, that the Employee class does not have any information about

salary and how much his pay comes to. It is safe to say, that no

employee of our organisation would like to be strictly an object of

Employee. This means, although we need the Employee class as a

parent of Salary and Hourly to support inheritance, we do not want to

create any objects of this class.

We can make it, so that no one can create objects of Employee class,

by declaring the Employee class abstract. The only result of making

the Employee class abstract is that we can no longer create objects of

Employee.

If the Employee class is made abstract, the following statement will

not compile –

Employee e;

e = new Employee(“George W.”,”Houston”,43); //Error

Just like you can make a class abstract, you can also make a method

abstract. For example, we could have a computePay() method in the

Employee class as abstract.

Page 37: Learn C#

33 | P a g e

Learn C# - do it yourself way... 2008

An abstract method is never called. Think about it. If computePay() is

abstract in the Employee() class, we really don’t care what

computePay() does in the Employee class, because it will never be

invoked/called. So, the abstract computePay() method in the

Employee class will be empty. Our assumption is that the child

classes of Employee will override the computePay().

This is where abstract methods are useful. If you want a class to

contain a particular method, but you want the actual implementation

to be determined by the child classes, you must declare the method in

the parent class as abstract. Abstract methods consist of a method

signature, but no method body.

public abstract class Employee

{

public string name;

public string address;

public int SSN;

public int number;

public abstract void computePay();

}

8.4 Sealed Keyword

Sealed keyword works exactly opposite to abstract.

- A Sealed class cannot be sub-classed.

- A Sealed method cannot be overridden.

8.5 Namespaces

Every class belongs to a namespace. Namespaces basically have two

purposes –

1. Namespace provides a mechanism for organising classes.

2. Namespace does compartmentalization.

When developing a C# program, you put classes that go together in

the same namespace. For example, in C# the classes that are used to

Page 38: Learn C#

34 | P a g e

Learn C# - do it yourself way... 2008

perform basic Input and Output are in System namespace. The classes

used for GUI applications are in System.Windows.Forms namespace.

The classes used for creating threads are in System.Threading

namespace.

Q. Why are namespaces necessary? What if I have a small program

that is only a dozen classes?

Namespace is more than just a mechanism for organising classes. A

more important aspect of namespaces is that they create

compartments. For example, suppose that your program contains a

class named Vehicle. What if I wrote a class Vehicle as well? How

would you be able to tell them apart. What if someone wanted to use

my Vehicle class and your Vehicle class in their program?

Q. I have seen this problem before. Why don’t you change the names

of the classes, such as Vehicle1 and Vehicle2?

No thanks. I would have to re-write and re-compile a bunch of code.

With namespaces, I don’t have to worry about it. If the two Vehicle

classes are in different namespace/compartments, my C# program can

distinguish between the two Vehicle classes.

8.6 Adding a class to a Namespace

To add a class to a namespace/compartment, we use the namespace

keyword.

namespace A{

...

}

For example, if you wanted to put Employee, Salary and Hourly

classes in the payroll namespace/compartment we can do it as follows

Page 39: Learn C#

35 | P a g e

Learn C# - do it yourself way... 2008

using System;

namespace payroll

{

public class Employee

{

//Body of the class

}

public class Salary : Employee

{

//Body of the class

}

public class Hourly : Employee

{

//Body of the class

}

}

The Employee, Salary and Hourly classes are now all in the same

namespace.

8.7 Compartments created by

Namespaces

Namespace creates a compartment for all classes. If we put a class

inside a namespace/compartment, the namespace becomes a part of

the name of the class. Say for example, when we put Employee class

inside payroll package, the name of the class now becomes

payroll.Employee

The Employee class can now no longer be accessed by the name

Employee. To refer to the Employee class, we must everytime call it

payroll.Employee. Similarly, we must refer to Salary and Hourly

classes as payroll.Salary and payroll.Hourly.

Suppose you have a written a Vehicle class, and I too have written a

Vehicle class. Kate wants to use both the Vehicle classes in their

program. So, I put my Vehicle class in a compartment quasar, and you

put your vehicle class in another compartment student. Kate will now

refer to both the Vehicle classes as,

Page 40: Learn C#

36 | P a g e

Learn C# - do it yourself way... 2008

quasar.Vehicle

student.Vehicle

To create objects of these classes, Kate would write

quasar.Vehicle v1 = new quasar.Vehicle();

student.Vehicle v2 = new student.Vehicle();

Here, v1 refers to a quasar.Vehicle object, whereas v2 refers to

student.Vehicle object.

Thus, from the above example, you can deduce the fact that,

namespaces help you to avoid naming conflicts by creating

compartments.

Note – Classes within the same namespace/compartment do not need

to use the <namespace>.<class-name> convention while referring to

each other. Thus, if write another class Test inside payroll namespace,

we can call Employee, Salary and Hourly classes directly without

using any special naming convention. Classes in the same

compartment find each other without any special syntax.

8.8 using Keyword

If a class wants to refer to another class within the same

namespace/compartment, the namespace need not be used. We could

refer to it directly.

However, outside the compartment, we must use the fully qualified

name of the class. Consider the following program :

using System;

namespace payroll

{

public class Employee

{

public string name;

public string address;

public int SSN;

public int number;

Page 41: Learn C#

37 | P a g e

Learn C# - do it yourself way... 2008

public Employee(string n, string a, int ssn, int num)

{

name = n;

address = a;

SSN = ssn;

number = num;

}

}

}

There is another class Boss which would like create Employee

objects.

using System;

class Boss

{

public static void Main()

{

payroll.Employee e = new payroll.Employee("Jane Smith", "111 Oak

drive", 999001111, 1);

}

}

Writing payroll.Employee everytime could become tedious or

cumbersome. To make things easy, we can use the using keyword.

using keyword specifies in which namespace to look for the given

classes. If you write using payroll, then we can refer to the Employee

class, simply as Employee without using the fully-qualified name.

using System;

using payroll;

class Boss

{

public static void Main()

{

Employee e = new Employee("Jane Smith", "111 Oak street",

999001111, 1);

}

}

Note that, using keyword is just a convenience statement. During

compilation, the C# compiler will replace all instances of Employee

class with payroll.Employee(Fully-Qualified name).

Page 42: Learn C#

38 | P a g e

Learn C# - do it yourself way...

8.9 Skeleton of a C# Executable

8.10 Interfaces

An interface is a collection of abstract

an interface thereby inheriting the abstract methods of the interface.

All the methods of an interface

Syntactically, an interface is defined using the C# interface keyword.

public interface IName

{

void method1();

void method2();

}

In the .NET Framework, interfaces have a special naming convention.

All interface names begin with a capital I.

Interfaces can have properties as well.

Difference from a class

1. You cannot create an object of an interface.

File1.cs

namespace A{....}

class A{//Body of class}

Skeleton of a C# Executable

Interfaces

An interface is a collection of abstract members. A class implements

an interface thereby inheriting the abstract methods of the interface.

All the methods of an interface need to be defined in the class.

Syntactically, an interface is defined using the C# interface keyword.

In the .NET Framework, interfaces have a special naming convention.

names begin with a capital I.

Interfaces can have properties as well.

Difference from a class –

1. You cannot create an object of an interface.

AssemblyMyProgram.exe

File1.cs File2.cs

namespace A namespace B{....}

//Body of class

class B{//Body of class}

class C{//Body of class}

namespace C{....}

File3.cs

2008

A class implements

an interface thereby inheriting the abstract methods of the interface.

need to be defined in the class.

Syntactically, an interface is defined using the C# interface keyword.

In the .NET Framework, interfaces have a special naming convention.

Page 43: Learn C#

39 | P a g e

Learn C# - do it yourself way... 2008

2. An interface does not contain any constructor.

3. All methods in an interface are abstract.

4. An interface can inherit multiple interfaces.

An interface is like a contract – a promise that a class will implement

a specific set of functionalities. When a class implements an interface,

it signs a contract, a treaty and promises to provide

implementation/definition of all methods or functions declared in the

interface.

C# code can question an object to determine whether it supports an

interface. Interrogating an object is basically asking the question,”Do

you support this interface?”. If the object answers, “Yes, I do!”, than

you can call the methods defined in the interface on the object.

8.11 Exposing Methods through an

Interface

public class Employee : Payable,EmployeeInfo

{

string name, address;

double weeklyPay;

public Employee(string n, string a)

{

name = n;

address = a;

}

public string GetName()

{

return name;

}

public string GetAddress()

{

return address;

}

public void SetName(string n)

{

name = n;

}

public void SetAddress(string a)

{

address = a;

}

Page 44: Learn C#

40 | P a g e

Learn C# - do it yourself way... 2008

public double GetWeeklyPay()

{

return weeklyPay;

}

public void computePay(int hoursWorked)

{

weeklyPay = hoursWorked * 6.50;

Console.WriteLine("Weekly Pay for : " + name + " is Rs." +

weeklyPay);

}

public void MailCheck()

{

Console.WriteLine("Mailing check to : " + name + " at " + address);

}

}

An organisation has many employees working in it. The Employee of

an organisation is represented by an Employee class object.

Associated with every Employee is his personal information such as

his name, address. Every employee also has a salary and other pay-

related information. The organisation has two departments – Payroll

and Human Resource.

Different parts in an organisation have different data needs. For

example, the payroll department handles the payroll needs, but it does

not need access to or change the personal information of an employee.

On the same lines, the Human Resource department manages the

general information about Employees, but it does not need access to

the Employee’s pay details. How do we realise these business rules in

C#? The answer lies in the innovative use of Interfaces.

Although we cannot instantiate(create an object) an interface, we can

do the following –

Page 45: Learn C#

41 | P a g e

Learn C# - do it yourself way... 2008

interface MyInterface

{

void a();

void b();

}

class MyClass : MyInterface

{

void a(){

Console.WriteLine(“Inside A”);

}

void b(){

Console.WriteLine(“Inside B”);

}

void c(){

Console.WriteLine(“Inside C”);

}

}

Declare an interface reference

MyInterface iref;

Assign to it, an object of a class that implements this interface

iref = new MyClass();

Using iref, we can call the methods a() and b(), but we cannot call the

method c(). Thus, we can call only those methods on the object,

which are declared and exposed by the interface.

Thus, by assigning an object to an interface reference, we can restrict

access to the methods that can be called on the object.

In the Employee class example, we could take two different interfaces

payable and EmployeeInfo for the Payroll and HR departments. The

payable interface exposes and provides an interface to only those

Page 46: Learn C#

42 | P a g e

Learn C# - do it yourself way... 2008

methods that are needed by the payroll department. Through the

EmployeeInfo interface, the HR department can only access those

methods which help it to manage Employee Information like name

and address.

public interface Payable

{

void computePay(int hoursWorked);

void MailCheck();

double GetWeeklyPay();

}

public interface EmployeeInfo

{

string GetName();

void SetName(string name);

string GetAddress();

void SetAddress(string address);

}

To represent the Payroll and Human Resource Departments, we write

the Payroll and HumanResource classes.

public class Payroll

{

public void PayEmployee(Payable p)

{

p.computePay(10);

p.MailCheck();

}

}

public class HumanResource

{

public string GetInfo(EmployeeInfo e)

{

return e.GetName() + " " + e.GetAddress();

}

public void ChangeName(EmployeeInfo e, string n)

{

Console.WriteLine("Changing Name for : " + e.GetName());

e.SetName(n);

Console.WriteLine("New name is : " + e.GetName());

}

public void UpdateAddress(EmployeeInfo e, string a)

{

Console.WriteLine("Changing address for : " + e.GetName());

e.SetAddress(a);

Console.WriteLine("New address is :" + e.GetAddress());

}

}

Page 47: Learn C#

43 | P a g e

Learn C# - do it yourself way... 2008

Now, we write the Main Program, where we take a fictious

Employee, and the payroll and HR departments.

class EmployeeManagement

{

public static void Main()

{

Employee e = new Employee("George Washington","Mt. Vernon");

Payroll payroll = new Payroll();

HumanResource hr = new HumanResource();

payroll.PayEmployee(e);

hr.GetInfo(e);

hr.ChangeName(e, "Bill Gates");

hr.UpdateAddress(e, "Redmond VA");

}

}

Page 48: Learn C#

44 | P a g e

Learn C# - do it yourself way... 2008

9

File Reading and Writing – I/O

9.1 Concept of Streams

Many applications which you would write, need to store data and

retrieve data from a file. For example, in an Employee Management

System, you would like the Employee details to be stored

permanently in a file on the disk. You would also want to read

Employee data from the file on disk. You might also need to update

an employee’s information in a file, say for example his salary is

raised, or his marital status changes from single to Married.

Reading or writing data to files is a functionality which you require

often while making your application. Thus, it is important that we

study, how we can read or write to files.

However, an application cannot directly read or write data to a file.

To connect an application to a file, we must use a virtual pipe. Just as

a real pipe carries water, the virtual pipe carries bytes of data to and

fro between the application and the file.

This virtual pipe in C# is called a Stream. If the stream connects to a

file, its called FileStream.

Page 49: Learn C#

45 | P a g e

Learn C# - do it yourself way...

To create a FileStream in C#, we must create an object of t

FileStream class.

FileStream fs = new FileStream(<file

access>,<file-Share>)

The FileStream constructor accepts the FileName as the first

argument. This must be the absolute file path. Next,

must be specified. The

would like to operate the file in.

The FileMode enum looks like this

enum FileMode{

CreateNew,

Create,

Open,

OpenOrCreate,

Truncate,

Append

}

Create always creates a new file. CreateNew create a ne

the file already exists, it overwrites the old file. OpenOrCreate works

in 2 ways – if the file does not exist, it creates the file, if the file exists

To create a FileStream in C#, we must create an object of t

FileStream fs = new FileStream(<file-name>,<file-mode>,<file

The FileStream constructor accepts the FileName as the first

argument. This must be the absolute file path. Next, the file mode

must be specified. The file mode tells the C# system, which mode you

would like to operate the file in.

The FileMode enum looks like this –

Create always creates a new file. CreateNew create a new file, and if

the file already exists, it overwrites the old file. OpenOrCreate works

if the file does not exist, it creates the file, if the file exists

2008

To create a FileStream in C#, we must create an object of the

mode>,<file-

The FileStream constructor accepts the FileName as the first

the file mode

file mode tells the C# system, which mode you

w file, and if

the file already exists, it overwrites the old file. OpenOrCreate works

if the file does not exist, it creates the file, if the file exists

Page 50: Learn C#

46 | P a g e

Learn C# - do it yourself way... 2008

it will open the file. Open simply opens the file. Append is used to

append whatever you write/delete to(from) the end of the file.

FileAccess enum specifies whether you would like to read from the

file, write to the file or do both ; ReadWrite.

A FileStream attached to a file, is all you need to do operations like

adding data, modifying data and deleting data from a file. To write to

a FileStream, we can call its Write() method. Before reading from the

stream, we must reset the internal position of the stream(using

Position property) and call the ReadByte() method.

Directly reading and writing bytes to a file can become tedious as it

demands that you work directly with bytes. Reader and Writer objects

encapsulate(hide from you) the detailed process of reading and

writing, and provide a higher level abstraction to you.

9.2 Concept of Reader and Writer

Once a FileStream has been hooked up to a file, we can read or write

to the FileStream object. However, we directly do not read or write to

the stream. We use Reader and Writer objects to read-write to the

FileStream. To read, the Reader object reads from the FileStream,

fetches whatever there is in the FileStream into a buffer/temporary

memory. Similarly, a writer object is used to write bytes to a

FileStream.

Lets study a simple program to write a few lines of text to a file.

using System;

using System.IO;

class WriteDemo

{

public static void Main()

{

Console.WriteLine("Enter the file you want to write to : ");

String path = Console.ReadLine();

Console.WriteLine("What do you want to write ? ");

String textToWrite = Console.ReadLine();

Page 51: Learn C#

47 | P a g e

Learn C# - do it yourself way... 2008

FileStream stream = new FileStream(path, FileMode.Create,

FileAccess.Write);

StreamWriter writer = new StreamWriter(stream);

writer.Write(textToWrite);

writer.Close();

stream.Close();

}

}

The above program asks the user to enter the path, where he would

like to store the file. It then asks the user to enter some text to be

written to the file. A FileStream object is created and hooked to the

file in the specified path, with the Create FileMode and Write

access(as we want to write text to the file).

A writer object is created. There is a class StreamWriter in C# that

represents the concept of writer. To model a writer, we must create an

object of the StreamWriter class. While creating a StreamWriter

object, we must pass as an argument to the constructor, the stream, we

would like the StreamWriter object to write to.

The writer object is now the tool that you would use to actually write

things to a file. You do so by calling the methods of the StreamWriter

object.

To simply write text, we use Write() method. WriteLine() method

always write the text onto a new line each time. To the Write() and

WriteLine() methods you can pass the text that you would like to

write as a String object.

After you’re done with writing text to the file, it is very important to

remember that we must unhook the FileStream from the file. If you

forget to do this, even after the program is over, the file will remain

blocked by the FileStream, so no other program which needs access to

the file will be able to access it. To do so, we close the FileStream and

StreamWriter objects, by calling their Close() methods.

Page 52: Learn C#

48 | P a g e

Learn C# - do it yourself way... 2008

9.3 Simple Program to read from a file

using System;

using System.IO;

class ReaderDemo

{

public static void Main()

{

FileStream stream = new FileStream("C:\\abc.txt", FileMode.Open,

FileAccess.Read);

StreamReader reader = new StreamReader(stream);

string input = null;

while ((input = reader.ReadLine()) != null)

Console.WriteLine(input);

reader.Close();

}

}

To read from a file, one must first create a FileStream object and hook

it upto the file, open the file in read-mode. Next, we take a

StreamReader object and pass to its constructor the stream, we would

like to read from.

We read one line at a time, by calling ReadLine() method on the

reader object. Thus, the entire file is read line-by-line till we do not

encounter the end of the file, where the input read is null. Finally, we

close the StreamReader object.

9.4 Using the Seek() Method

The Seek() method can be used to skip bytes in FileStream, and move

the cursor ahead in the stream, by specifying an offset. This is helpful,

if you don’t always want to start reading from the beginning of the

file, but maybe at 10 bytes from start of file.

using System;

using System.IO;

class ReaderDemo

{

public static void Main()

{

Page 53: Learn C#

49 | P a g e

Learn C# - do it yourself way... 2008

FileStream stream = new FileStream("C:\\abc.txt", FileMode.Open,

FileAccess.Read);

StreamReader reader = new StreamReader(stream);

string input = null;

stream.Seek(12, SeekOrigin.Begin);

while ((input = reader.ReadLine()) != null)

Console.WriteLine(input);

reader.Close();

}

}

Given the above abc.txt file, we get the following output, when we

specify the offset = 12 bytes from the beginning.

If we modify the Seek() function as –

stream.Seek(10, SeekOrigin.Begin);

stream.Seek(2, SeekOrigin.Current);

The output is still the same, SeekOrigin.Current move the cursor

ahead by 2 bytes from its current position. After the first call to Seek()

the cursor is at position 10. Thus, current position of cursor becomes

10. After the second call to Seek(), the cursor would reach 10+2=12th

position.

Page 54: Learn C#

50 | P a g e

Learn C# - do it yourself way... 2008

9.5 DirectoryInfo and FileInfo classes

The FileInfo class in C# allows you to access, manipulate and find

information about a single file on the Hard-disk. You can question the

file for various things such as name of the file – Name property, fully

qualified name – FullName property, last accessed time –

LastAccessTime property, size of the file – Length property,

extension - Extension property of the file etc.

class FileDemo

{

public static void Main()

{

FileInfo f = new FileInfo("C:\\abc.txt");

Console.WriteLine("File Name : " + f.FullName);

Console.WriteLine("File Attributes : " + f.Attributes.ToString());

Console.WriteLine("File Creation Time : " + f.CreationTime);

Console.WriteLine("File Exists : " + f.Exists);

Console.WriteLine("File last accessed : " + f.LastAccessTime);

Console.WriteLine("File Size : " + f.Length);

}

}

The DirectoryInfo class is used in a similar manner to find

information about a directory.

using System;

using System.IO;

class DirectoryDemo

{

public static void Main()

{

DirectoryInfo dir = new DirectoryInfo("C:\\");

Console.WriteLine("Directory Name : " + dir.FullName);

Console.WriteLine("Last Access Time : " + dir.LastAccessTime);

Console.WriteLine("Creation Time : " + dir.CreationTime);

Console.WriteLine("Attributes : " + dir.Attributes);

}

}

Page 55: Learn C#

51 | P a g e

Learn C# - do it yourself way... 2008

9.6 Enumerating the files in a Directory

We may use the DirectoryInfo and the FileInfo classes to find out the

contents of a directory. Let’s suppose, we are given a directory

C:\Windows and we would like to find what are the sub-directories

and files inside this directory.

To find the subdirectories in a given directory, we call the

GetDirectory() method. The result of calling this method is an array

of DirectoryInfo[]. Each element of the array represents a sub-

directory. Similarly, to find the files inside a Directory, we call the

GetFiles() method.

using System;

using System.IO;

class EnumeratingDemo

{

public static void Main()

{

DirectoryInfo dir = new DirectoryInfo("C:\\");

DirectoryInfo[] subDirs = dir.GetDirectories();

Console.WriteLine("Name " + "\t\t\t" + "Creation Time ");

foreach (DirectoryInfo d in subDirs)

{

Console.WriteLine();

Console.Write(d.Name);

Console.Write("\t\t\t"+d.CreationTime);

}

}

}

Page 56: Learn C#

52 | P a g e

Learn C# - do it yourself way... 2008

Page 57: Learn C#

53 | P a g e

Learn C# - do it yourself way... 2008

10

Threads, Processes,

AppDomains and

Multi-threading