#
Learn
The do-it-your elf way
Get the gist of the concept
Write the program See the output for yourself
Quasar S. Chu awalla
1|Page
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. 2|Page
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. 2|Page
Learn C# - do it yourself way...
2008
Contents Chapter 1 2 3 4 5 6 7 8 9 10 11 12
3|Page
Name
Introduction to C# C# Fundamentals Decision Making and Looping Constructs Classes, Objects and Methods Collections in C# Polymorphism, Constructors and Destructors Inheritance – Our objects’ family tree Advanced C# Language Concepts File Input and Output Threads, Processes, AppDomains and Multi-threading Exception Handling Assembly and Reflections
Pages 1 11
Learn C# - do it yourself way...
4|Page
2008
1 Introducti on to C#
Objectives To type a simp e program in C#, and acquaint yourself with e diting, compiling and running yo r program. How the Hello orld program works... Hey, Object Or ented Programming – the other day I heard these words from geek next door. Familiarize you rself with the concept of Objects and Classe . Have a dim an faint idea of Object Oriented features like A bstraction, Encapsulation, Polymorphism and Inheritance
This chapter serves as a preliminary introduction to stud ents who are new to C# paradigm. In C#, you can create two kinds of applications – Console Based Appl cations and Windows Applicatio s. Throughout the first half of this book, you will learn how to create a Console Application. Console pplications accept input and dis lay output in the form text. In cons le programs, generally, you will se the Console window to give inputs and see the output. Win dows Applications usually h ave a user-interface(GUI) throug which you give inputs and see ou puts.
1|Page
Learn C# - do it yourself way...
2008
In MS Windows 95/98, the console is called MS-DOS Prompt. In Windows XP, Vista, it is called the Command Prompt.
1.1 Simple Program to print text on the Screen Program that prints Hello World text on screen 1 using System; 2 3 class Greeting 4 { 5 public static void Main(string[] args) 6 { 7 Console.WriteLine("Hello World"); 8 } 9 }
You begin by punching in the above program in any text editor like notepad on Microsoft Windows. You save the file in a convenient location, say C:\ drive. Let’s save the file as Greetings.cs.
Once you are done with that, well go to Start => All Programs => Microsoft Visual Studio 2008 => Visual Studio Tools => Visual Studio 2008 Command Prompt. In the Command Prompt, navigate to the location, where you stored your Greetings.cs file. Once you reach there, To compile the program, type csc Greetings.cs To run the program, type Greetings 2|Page
Learn C# - do it yourself way...
2008
1.2 Dissecting the Hello World Program 1 using System;
Line 1 of the program reads using System. This is called a using Directive. It says that this program borrows some features from the System namespace. In C#, a namespace is a way to group related features together. A namespace contains some ready-made code, that is available at your disposal. You can refer to it and use it in your program, rather than re-writing it. You don’t have to re-invent the wheel everytime. Hold that for a moment now, I will explain it to you at length further ahead. Line 2 of the program is a blank line. Programmers often use spaces and blank lines to separate different sections of code, just as we leave space between two paragraphs in the English language. 1.1 Good Programming Practice You must use whitespaces, blank lines to make the program readable, so that others can easily comprehend it. 3
class Greeting
Lines 3-9 of the program consists of our first class. The dictionary meaning of the English word class is the category in which things fall. A number of things often share some common features and operations. For example, all color TV objects have features like volume, brightness, contrast, color and have operations such as increase/decrease volume, increase/decrease brightness, increase/decrease contrast etc. All such objects would fall in the 3|Page
Learn C# - do it yourself way...
2008
colorTV class. In this rogram, we’ve taken a class Gre ting. To specify that Greeting is a class, we write the class keyw rd before it. Keywords are word that have special meaning in the C# system. Thus, class keyword tells th computer that Greeting is a class . Line 4 is an opening c rly brace {. The curly brace indi ates the start of the class. When the class ends, we have to close the c lass by putting the corresponding } closing curly brace. The ma ter enclosed in the curly braces is c alled the class body. In C#, when you write a new class, you will al ays pack the body of the class in ide a pair of curly braces{...}. 1.1 Common Programming Error The number of opening curly races must equal the number of closing curl y braces. Many-atimes, naive programmers sta rt a curly brace, but forget to close it.
1.2 Good Programmi g Practice When typing a left opening br ce { , it is always better to type the right clos ing brace } , right away on the spur of the mome nt. You can then re-position your cursor bet een the two braces and start typing. This elps to prevent missing braces.
5
public static void Main(string[] args)
Line 5 is present in all C# programs. The word Main() indicates this is the start of the prog am. This is where the C# system starts executing(running) th program. Thus, Main() is the ent ry point(starting point) o any program. All statements wri ten inside Main() are executed o e by one, one line and the next li e and so on. The Main() block is st rted using a starting curly brace and terminated using an e ding curly brace }. Whatever you want to write inside Main() must be enclosed within this pair of curly braces. Main() is called a me hod /operation. Every method has a parenthesis (). Main is the name of the method. The co tents written inside Main() block is called method body.
4|Page
Learn C# - do it yourself way...
2008
1.3 Good Programmi g Practice The entire body of the class G reeting, that includes the Main() method is a t the first level of indentation. Indentation make s your program tidy and readable.
In the above program, we have written just one comma d/statement – Console.WriteLine(). his command is used display text on the VDU screen. Whatever you put inside Console.WriteLine() in the double quotes “ “ gets printed on the screen, when you run the rogram. In this case, it is Hello World. At the end of the state ent, there is a semi-colon. Just a s every English sentence ends with a full-stop, every statement i n C# ends with a semi-colon;. 1.2 Common Programming Error Forgetting to put the delimite ; after every statement is a committed quite often. As a rule, every C# statement must end ith a semi-colon. If you miss out any, your p rogram will not compile successfully. The C S arp Compiler csc will prompt you about the point, where it expects a semi-colon.
1.3 Common Programming Error C# is a case-sensitive langua e. Hence writing class as Class is an error. ll keywords like using, class, public, static, voi d, string are always in lowercase. The name of class, methods, and namespace should alway begin with a capital letter like Greeting, Sy tem, Main, WriteLine. In case of a multi- ord name like WriteLine, each letter of succ essive words like Write and Line must be capita lized.
1.4 Good Programmi g Practice The program written above is shown in an indented fashion. Although it is not necessary to give indents, it is a clean and neat way of writing a program. Giving inden tation or tabs, also gives an insight into which bl ck the statement belongs to – inner block or outer block. And the icing on the cake is, you c n make sure that you have closed all the cu ly braces and nothing is amiss. Indents enh nce the readability of the program.
5|Page
Learn C# - do it yourself way...
2008
1.3 What is Object – Oriented Programming (OOPS)? C# is an Object-Oriented Programming Language. 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. Programming languages such as C, Pascal, Basic, Fortran follow this approach. However, as problems grew large and complex, even the procedural programming approach gave way. It was not strong and robust enough to analyse large and complicated problems. The new approach to programming is Object-Oriented Programming. Object – Oriented Programming (OOPs) helps us to better model real world entities in the problem domain. In Object-Oriented Programming, to find the solution, we decompose a large problem in terms of objects. Object Oriented programming languages are Simula, Java, Smalltalk, C++, C# and many more.
1.4 What is an Object? 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 6|Page
Learn C# - do it yourself way...
2008
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. For example, my car might have the name Maruti, brand as Swift, yearOfManufacture as 2008, price as 3.5 Lac, color as Blue. An object primarily contains two things – data in the form of attributes and methods – things that operate on this data. We now know what attributes mean. What are methods? Well, in Object-Oriented Programming, we often like to change the values of the attributes. For example, 3 years down the lane, you would like to refurbish your car with a fresh new paint, make it waterrepellant using a good old teflon coating. Also, as years pass by the price of your car changes due to depreciation. The true price of your car is the depreciated value. Thus, we often need to change the attributes(data) inside the object. There are two ways to do this. First is, we go in and modify each value directly. However, this is not a good practice in Object – Oriented Programming. It is not a good practice to modify/access the attributes of an object directly. Instead, we access the attributes/data of an object through the methods in an object. Anything we would like to do, on an object’s data, we must do it through the methods. Methods act as an interface between the object (its data) and the outside world user. To model real-world things or entities, in C# we create Objects. Capsule of Data(Attributes) and Methods(Operations on Data) is an Object. Attributes are the characteristics of features that describe the object. Methods are used to manipulate the data/attributes of an Object. Not a good practice to access the attributes of an object directly. Do it through methods. Methods act as a broker, they have the license to access the attributes.
7|Page
Learn C# - do it yourself way...
2008
1.5 What are Classes? A class acts a blue-pri t, design or a layout for an objec . When an architect wants to buil houses, he does not directly buil d the house haphazardly. Instead, e first creates a basic plan or design. It could be an architectural drawing showing, what the houses w ill look like, how much carpet area they will have, dimensions, color etc. He then uses this design or pla as a blue-print or basis for const ructing the actual houses.
On the same lines, in #, we first create a design or a pl an called Class. Using this class /plan as a blue-print or base, we c onstruct actual objects. The class/plan tells us how the objects ar going to look like.. A class must specify hat attributes and methods will b there in an object. For example, before creating the different car ob ects, we must specify in the plan(cla s), what attributes and methods e very car object would have. We then construct Car objects, by assigning values to e ch of the Car’s attributes.
8|Page
Learn C# - do it yourself way...
2008
Thus, in C#, we must create a class(plan) and then use it a guideline(blue-print) to create objects. You cannot create objects without a class.
Also, merely defining a class is not enough. To be able to use it, we must create objects of the class. Just as having a drawing on paper is just a plan. To materialise this plan, we must utilize it to construct a building.
1.6 Abstraction Abstraction is the process of stripping down an onion, peeling off all the inessential layers, until you are left with the bare minimum essentialities, the kernel or core. Abstraction steers clear of all unimportant details and allows you to pay more emphasis on the important details. Abstraction is an important software design principle. A good class always exposes a minimal set of functionalities that allow you to manipulate the objects in an easy-to-use fashion. Let me cite to you an example of abstraction which you might already know. To transfer a file from your desktop PC to a USB flash drive, you would have to specify, where from to lift the file on the hard-disk, the track, the sector, the cluster, how many bytes to transfer, the destination location etc. With the help of an Operating System like Microsoft Windows, we just have to copy the file and paste it where we would like to. What an Operating System does is, it frees us from all the unessential details of hardware. Thus, it provides a higher level abstraction, and hides all the unnecessary details. Why abstraction is so important? Computer applications or software
are generally made of components or layers. As time progresses, new functionalities and features are added to them. When new layers are added, we would want that their impact on the older layers should be minimal. Minimal dependency is an absolute must. This is why abstraction is necessary. 9|Page
Learn C# - do it yourself way...
2008
1.7 Principle of Encapsulation In procedural programs, there are lots of data and functions. All the functions have access to all the data. The functions and data are separated/segregated from each other. In simple programs, this idea works well. However, with complex programs, this approach breaks down. When we make changes to the data, as a consequence all the functions that access this data will break down and give wrong results. So, we need change all the affected functions. So, in Object-Oriented Programming, we put data and its related functions into a single module. This process is called Encapsulation.
1.8 Inheritance In a family, a child inherits the features and traits of his parent, and parents inherit their features and characteristics from grand-parents. This way, certain features or attributes are passed on from generationto-generation. A similar tool is present in C# as well. An object can inherit attributes and methods from another object. The former is called the parent, and the latter is called the child. The child object has features and attributes of the parent. In addition to this, the child object can have some of its own features and attributes. Thus, a child is a specialised kind of a parent. They share a kind-of relationship.
1.9 Polymorphism Poly means many, morphos means form. Polymorphism means one thing exhibiting many forms. In polymorphism, an object behaves differently in different situations. Depending upon the context and environment, it changes its behaviour. 10 | P a g e
Learn C# - do it yourself way...
2008
2 C# Funda entals Objectives Learn how to s ore data in computer memory – use variabl s and constants Rules to be foll wed while you assign a valid variable name Declaring Vari bles in C# Data-types in # - They come in various sizes, and store di fferent types of data Assigning valu s to variables Learn with a si ple program to store and retrieve values of variables Operators in C Get your hands wet with learning how to use arithmetic ope rators wherever you want. Stud a simple program that calculates the Simpl e Interest
2.1 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 da a and output results in computer m mory, so that we can retrieve it f r later purposes. 11 | P a g e
Learn C# - do it yourself way...
2008
Before you get to kno , how this is done, let’s take brie f look at how Computer memory lo ks. Just like in a street, people liv e in houses, computer memory is organised as a series of cells. The ells do not house people, instead hey house data. We can visualise the picture of computer memory lik the one below :
Suppose we store the umber 2 in some memory location. Next time, suppose, we would lik e to retrieve the contents of this c ll. Then how to do that? How do w refer to this cell? The houses in street have different names. In a similar fashion, what we do is, we give a name to the memory locatio , say ‘a’. And then, we can access the contents of this memory locati n using the name ‘a’. Next time, simply have to say, “Give me the c ntents of the memory location w hose name is a..” and I’ll get the ou put = 2. Thus, one of the ways to access and manipulate the valu es(data) of a memory location is to give it a name. If the data stored i n a memory location is allowed to hange, for example if value in a an be changed to 3, such a emory location is called a Variable. We use the word Variable, because, the contents of such a cell can ary. On the other hand, at t imes, we would like to contents o a cell to remain fixed or constant, not allowing it to change. For xample, if a 12 | 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.
2.2 Rules for naming a Variable Unlike babies, we don’t have full liberty while naming a variable. A valid variable name must satisfy the following rules. 1. Name of a variable must begin with an alphabet[A-Z,a-z] or underscore_. 2. The successive characters of a variable can consist of alphabets[AZ][a-z], digits[0-9] or underscore sign _. 3. The name of variable must not be a reserved keyword (like int, char, float, double etc.)
2.3 Variables Declaration The Operating System is a miser. The OS does not lend any bytes for free. Even if you want a single byte of memory, you must first ask the OS for it. Hence, the OS protects the computer memory. Its job is to act as a Memory manager. When you want some memory space to store data, you must first ask the operating system for it. If the OS grants your request, you can go ahead and store data in that memory location. You must tell the OS how much memory(in bytes) you need for doing your work(like storing data in variables). Once the OS agrees to your request, it reserves memory space for you. This memory space is then reserved for you, and no other program can access it.
13 | P a g e
Learn C# - do it yourself way...
2008
Telling the OS how many bytes of memory you need is called Declaration. While making this declaration/announcement you must specify two important things – 1. How many bytes of memory you would need to store your data? 2. What name you would give to this newly reserved memory location, so that you can refer to it, the next time round by this name. As far as the former is concerned, the bytes of memory you would need to store the data really depends on the type of data that you are going to store. A number like 3.14159 needs more memory that just a 3. What type of data you intend to store, can be indicated by specifying the data-type.
2.4 Data-types in C# Some of the primitive data-types in C# are shown in the table. bool is used to store boolean values – just two possibilities 0 or 1 that is true or false. char is used to store single characters like A, B, C, ..., a, b, c,.., ‘1’,’2’,.. and also, ‘ ‘, ‘$’, ‘_’ and all the letters you would find on the keyboard that have an ASCII value. In C#, char stores the data in Unicode Text Format(UTF). To store integers or numbers without a decimal point, we have four data-types available – byte, short, int, long. byte as the name suggests is 1 byte long. So, it can store numbers from 0 to 255. But, what if we wanted to store a larger number like 256. We would then require more than 1 byte of memory space; 2 bytes. So, we use the short data-type. short data-type can store number ranging from -32,768 to +32,767. What if we want to store a still larger number like 50,000? We can then use the int data type(4 bytes) which allows us to store numbers upto 2 billion. If we would like to store a number like a googol, (which is one followed by 100 zeroes), what do you do? You can use a data-type long – 8 bytes. To store decimal(real) numbers like 2.5, -3.821 etc. we can use the float and double data-types. 14 | P a g e
Learn C# - do it yourself way...
Data-type
Storage Space
Bool Char Byte Short Int
2 bytes 1byte 2 bytes 4 bytes
Long Float Double Decimal
8 bytes 4 bytes 8 bytes 8 bytes
2008
Range of Values
Example
true,false \u0000 to \uFFFF 0 to 255 -32,768 to +32,767 -2,147,483,648 to +2,147,483,647 -9.22e18 to +9.22e18
bool b = true; char ch = ‘A’; byte b = 10; short s = 1000; int i = 500; long l = 1000; float f = 3.14F; double d = 25.583
Apart from these, we have sbyte(signed-byte), ushort(unsigned short), uint(unsigned int) and ulong(unsigned long).
2.5 Filling values in a variable We first declare the variables we want. To declare a variable, we use the following syntax : ; int myVariable; In the above example, we declared a variable having data-type int(4 bytes) and we named the variable “myVariable”. To begin with, myVariable is right now empty. In other word, myVariable contains 0. To use myVariable, we must put meaningful data in it. Let’s store the number 5 in the integer variable called myVariable. myVariable = 5; Thus, it is a two-step process :
15 | P a g e
Learn C# - do it yourself way...
2008
Declare a variable with the desired data-type(depending on what data you would like to store)
Assign valu to the variable, by using =(equal to) sign.
2.6 Code Sni pet – How to store and retrieve valu es from variable Here’s a simple progr m that illustrates how to declare variable, assign values to it, an later retrieve the contents of the ariable. Program that stores and displays the value in a variable 1 using System; 2 3 class VariablesDemo 4 { 5 public static void Main() 6 { 7 /*Declare a bool variable*/ 8 bool b; 9 10 /*Store a value in it*/ 11 b = true; 12 13 /*Display the value in b*/ 14 Console.WriteLine("b = {0}", b); 15 16 /*Declare a character variable*/ 17 char c; 18 19 /*Store a single character in it*/ 20 c = 'M'; 21 22 /*Display the character stored in c*/ 23 Console.WriteLine("c = {0}", c); 24 25 /*Declare an integer variable*/ 26 int i; 27 28 /*Store an integer number in it*/ 29 i = 10;
16 | P a g e
Learn C# - do it yourself way...
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 }
2008
/*Display the integer value stored in the variable*/ Console.WriteLine("i = {0}", i); /*Declare a float variable*/ float f; /*Store a real number in it*/ f = -0.0125f; /*Display the value of f*/ Console.WriteLine("f = {0}", f); /*Declare a double variable*/ double d; /*Store a large real number in it*/ d = 254.1459; /*Display the value of d*/ Console.WriteLine("d = {0}", d); }
Upon running this program, we get the following output –
You need to understand, how Console.WriteLine() function works. WriteLine() function is used to display text on the console (command prompt). Whatever is given to WriteLine() in double quotes “ ---“ is displayed on the command prompt. The second aspect is the use of placeholders. Notice that we’ve put {0}’s in the WriteLine() function in the above program. {0} is called a place-holder. How it works? int a = 2, b = 3, c = 4; Console.WriteLine("a = {0},b = {1}, c = {2}", a, b, c);
17 | P a g e
Learn C# - do it yourself way...
2008
Assume that we take t ree integer variables a,b and c. e’ve put the values 2,3 and 4 in the variables a, b and c respectively. To display their values, we use the WriteLine() function. In the Wr teLine(), we give a,b and c as argu ents without the double quotes. This means that we want to displa the contents of a,b and c. So, th values 2,3 and 4 will be displaye . {0} gets substituted by the valu e of a – 2, {1} by the value of b – 3, nd the placeholder {2} by the val ue of the variable c – 4. Output of the above c de snippet :
2.6 Operators In our school and pre- chool, we have studied math. Op erations like adding, subtracting, multiplying, dividing are pretty co mon. Like in algebra, we have man different operators in C#. Class of Operators Binary Arithmetic Op rators Unary Arithmetic Ope rators Logical Operators Relational Operators Bitwise Logical Oper tors Shift Operators Assignment Operators
18 | P a g e
+, - ,*,/,% + , - , ++ , -&&, || , ! , ^ <,<=,>,>=,==,!= &,|,~ <<, >> = Shorthand Assignment +=, -= , *= , /= , %= , &=, |= , =, <<= , >>=
Learn C# - do it yourself way...
2008
2.7 Binary Arithmetic Operators Binary operators are the ones which operate on two operands. Binary Arithmetic operators are plus +, minus - , multiplication *,division / , and Modulo %. Just as we write expressions in algebra, we can form arithmetic expressions in C#. Let’s begin with a few simple examples. int a = 5, b = 10; int res; res = a + b; Console.WriteLine(" a + b = {0}", res);
The result of adding a + b, should be 5+10 = 15. So, res contains the value 15. Similarly, res = b - a; Console.WriteLine("b - a = {0}", res);
To subtract b – a and store the result in res, we write the above lines. The effect of this statement would be, 10-5 = 5, and hence res = 5. res = a * b; //res = 5*10 = 50 Console.WriteLine("a * b = {0}", res); res = b / a; //res = 10/5 = 2 Console.WriteLine("b / a = {0}", res);
Thus, we could write any complex instruction like res = a + b * c – d / e. Let’s write a simple program that calculates the simple interest. Program to calculate Simple Interest 01 using System; 02 03 class SimpleInterestDemo 04 { 05 public static void Main()
19 | P a g e
Learn C# - do it yourself way...
06
2008
{
07 08 09 10 11 12 13 14 }
int principal = 10000; int noOfYears = 5; int rateOfInterest = 10; int SimpleInterest = (principal*noOfYears*rateOfInterest)/ 100; Console.WriteLine("Simple Interest = {0}", SimpleInterest); }
This simple program takes three variables principal, noOfYears, and rateOfInterest, and computes the simple interest by using the formula PNR/100. Upon running the program, we get the following output.
When we divide two numbers, the divide operator / is used to find the answer(quotient) of division. For example, when we divide 11 by 3, we get quotient 1 and remainder 2. Thus, 11/3 = 1(quotient) and 11 modulo 3 = 2(remainder). Modulo operator is used to find the remainder of the division operation. Program that shows the use of % operator 01 02 03 04 05 06 07 08 09 10 11 12 13
using System; class ModuloDemo { public static void Main() { int a = 11; int b = 3; int remainder = a % b; Console.WriteLine(" 11 % 3 = {0}", remainder); } }
Upon running the program, we get the following output.
20 | P a g e
Learn C# - do it yourself way...
2008
Let’s study a simple program, that uses the modulo operator % to reverse a four-digit number. For example, if the input number is 1234, the output should be the number 4321. Program to reverse a 4-digit number 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18
using System; class ReverseDemo { public static void Main() { int number = 1234; int int int int
u = number % 10; t = (number / 10) % 10; h = (number / 100) % 10; th = (number / 1000) % 10;
int reverse = u * 1000 + t * 100 + h * 10 + th; Console.WriteLine("Original = {0}", number); Console.WriteLine("Reverse = {0}", reverse); } }
The line 5 in the Main() program declares a variable called number, and we store in it the value 1234. To calculate the reverse of a number, the algorithm is as follows – a. Input number – n b. Extract various digits of the number n. c. Form the reverse number as (Units-digit x 1000) + (Tens-digit x 100) + ( Hundreds-digit x 10) + (Thousands-digit x 1)
So, we must extract the various digits from one thousand, two hundred and thirty four as 1, 2, 3 and 4. We then form the reverse of this number as 4 x1000 + 3 x 100 + 2 x 10 + 1 x = 4321. Line 14 in the program corresponds to this step. 21 | P a g e
Learn C# - do it yourself way...
2008
Lines 9 – 12 are used to extract out the individual digits from the 4digit number. How do you that? Well, it seems weird at first sight. But, here goes. You divide a number like 1234 by 10, and find the remainder. In that case, 1234 modulo 10 = 4. (as 1230 is perfectly divisible by 10; 1234 is 1230 + 4 left over) Thus, number % 10 gives the units digit. Now, to extract the tens digit, we would use the same technique – number % 10. However, to extract 3 from 1234, we first divide 1234 by 10. 1234 / 10 = 123 (Truncating 123.4 to 123...) Now, this number 123 % 10 = 3. Thus, we pulled out the tens digit. To pull out hundred’s digit(2), 1234 / 100 = 12 12 % 10 = 2. To pull out thousand’s digit(1), 1234 / 1000 = 1 1 % 10 = 1. Upon running the above program, I get the following output.
2.9 Precedence and Associativity of Arithmetic Operators When an arithmetic expression is evaluated in C#, there is an ambiguity in how the result of the expression is calculated. For example, the statement : 22 | P a g e
Learn C# - do it yourself way...
2008
result = 2 * 3 + 4; It may be evaluated as – result = 2 * 3 + 4 =6+4 = 10 result = 2 * 3 + 4 =2*7 = 14 To resolve the ambiguity, C# assigns a priority to all the operators. (This does not only apply to arithmetic operators, but all kinds operators, however in this book, our discussion is restricted to arithmetic operators) Operators with higher priority are evaluated first and are preferred over operators of lower priority. The priorities of different operators is shown in the table below. This is also called precedence of operators. Priority st 1 Priority
Operators */%
nd
+-
rd
=
2 Priority 3 Priority
Description Multiplication, Division, Modulo Addition, Subtraction Assignment
Thus, in the expression result = 2 * 3 + 4 We first evaluate Multiplication *, because it has the highest priority. So, result = 6 + 4
23 | P a g e
Learn C# - do it yourself way...
2008
Next, we evaluate addition +, because + has higher priority over =, and hence + operator precedes over =. result = 10. Lastly, we evaluate the = equals operator. In other words, the value 10 is now stored in the variable result. Now, consider the following expression – result = 5 * 4 / 2 ; In this case, * and / have the same priority level. When two operators have the same priority, which operator should be evaluated first? The answer to this question lies in a concept called associativity. Associativity indicated the direction in which the expression is scanned to evaluate the operators. The associativity of arithmetic operators is given in the table below – Operators +-*/% =
Associativity Left – to – Right Associativity Right – to – Left Associaitivity
In the expression, result = 5 * 4 / 2 ; Since, = equals operator has R – to – L associativity, we will first evaluate the right hand side(RHS) and then assign the result to the LHS. The RHS is 5 * 4 / 2. Since, * and / have the same priority, we shall have to consider their associativity. Both * and / have L – to – R associativity, we start scanning the expression in left – to – right direction and evaluate the answer. In left – to – right order, we first encounter *, so 5 * 4 = 20.
24 | P a g e
Learn C# - do it yourself way...
2008
Then we encounter /. So we evaluate it as, RHS = 5 * 4 / 2 = 20 / 2 = 10. Finally, the result of the expression on the RHS is assigned to the variable result on the LHS. Thus, the value 10 is stored in result.
2.10 The arithmetic expression a = a + b You are familiar with most of the algebraic expressions like : =+ = 3.14 ∗ ∗ = + + + + ⋯ 2 4 8 = + ∗ − / They all have, some algebraic variables on the RHS, whose result of computation is the LHS. But, you may not see in algebra, an expression like : =+1 =2∗ =+ This might be absurd in terms of algebraic expression, but they are perfectly valid C# arithmetic expressions. In C#, you can have the same variables on the left hand side and right hand side of an arithmetic expression. How to decipher the meaning of the above expression? In an arithmetic expression, as a rule, we always first evaluate the RHS, and the result of the expression on the RHS is assigned to the LHS. Consider = + 1. Initially, suppose the variable a contains 2. ∴ 1 ℎ + 1 = 2 + 1 = 3. 25 | P a g e
Learn C# - do it yourself way...
2008
This value 3 is now stored back in the variable a(LHS). Note that, one variable can contain hold one value at a time. So, the old value 2 is lost and it is over-written with the value 3. Thus, this expression increases the value of a by 1. In other word, it increments the value of 1. Similarly, if we would like to decrease the value of a by 1, we would have to write = − 1. The expression = ∗ 2 doubles the value of a and stores the result in a. For example, to begin with if a = 5, after this statement executes a will hold the value 10.
2.11 Unary Arithmetic Operators Unary operators are the ones that operate only one operand at a time. The different arithmetic unary operators are unary plus +, unary minus -, increment ++ and decrement -- operators. Unary plus and minus are easy to understand. If a = 2, if we write a = +a ; a would hold the answer 2. a = -a ; a would hold the answer -2. Unary plus really has no meaning. It is there only for the purpose of symmetry. The increment operator ++ is a shortcut way to increase the value of a variable by 1. In other words, = + 1 can be simply written as + +. Similarly, to decrement the value of a by 1, we simply write − −. Given below is simple program that illustrates how increment ++ and decrement -- operators work.
26 | P a g e
Learn C# - do it yourself way...
2008
Program to show the working of ++ and -- operator 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
using System; class IncrementDecrementDemo { public static void Main() { int a = 2; Console.WriteLine("Initially a = {0}", a); //Increment the value of a a++; Console.WriteLine("After incrementing a = {0}", a); //Increment the value of a a++; Console.WriteLine("After incrementing a = {0}", a); //Decrement the value of a a--; Console.WriteLine("After decrementing a = {0}", a); //Decrement the value of a a--; Console.WriteLine("After decrementing a = {0}", a); } }
This program takes a variable called a. The variable a is initialised to 2. We increment the value of twice. We then decrement it twice. In each step, we print the result of increment/ decrement to the screen. The output appears as follows :
2.12 Relational(Comparision) Operators Relational (comparision) operators are simple to use. They always return a bool – true or false value. Relational operators operate on simple variables as well as they can operate on complex expressions. The different relational operators are < , > , <= , >= , == , != . 27 | P a g e
Learn C# - do it yourself way...
2008
Let’s take simple examples and try to understand the above operators. x = 10 x=8 x=-5 x = 4, y = 3 x=9 x=5
x>5 2*x < 20 -x >= 10 x + y <=9 x + 1 == 10 x!=5
true true false true true false
2.13 Logical Operators Just as we have plenty of arithmetic operators, we have yet another important class of operators called Logical Operators. Logical operators are also called Conditional Operators. The various logical operators are Logical AND && , Logical OR || , Logical Exclusive OR ^ , Logical NOT ! . Logical operators are very useful in everyday situations. They can be used to combine two or more conditions. Say for example, we have a variable x initialised to 10. X 10
x >5 true
x<15 True
x>5 AND x<15 true – since x lies in the range {5,15}.
The Logical AND operator returns a bool value true or false. If both the conditions(operands) are true, the answer is true. The logical AND operator in C# is written as &&. A true true false false
28 | P a g e
B True false true false
A && B true false false false
Learn C# - do it yourself way...
2008
The Logical OR operator returns a bool value true or false. Logical OR in C# is written as || (Two vertical bars). The logical OR || returns true even if any one of the condition holds true. A true true false false
B True False True False
A || B true true true false
The Logical XOR(Exclusive – OR) operator also returns a bool value – true or false. The logical XOR is a special case of the logical OR operator and is written in C# as ^. Logical XOR returns true only if the conditions(operands) are dissimilar. If they are similar, it returns false. A true true false false
B True False True False
A^B false true true false
Logical NOT ! operator negates or complements the condition. If the condition evaluates to true, !(condition) would be false. On the other hand, if the condition evaluates to false, !(condition) would be true.
Given below is a program that shows how to work with all the logical operators. Program to show the working of && , || , ^ and ! operators 01 using System; 02 03 class LogicalDemo 04 { 05 public static void Main() 06 { 07 int x = 10; 08 Console.WriteLine("x = {0}", x); 09 10 bool ans = (x > 5) && (x < 15); 11 Console.WriteLine("x > 5 && x < 15 = {0}", ans);
29 | P a g e
Learn C# - do it yourself way...
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 }
2008
ans = (x > 5) && (x > 15); Console.WriteLine("x > 5 && x > 15 = {0}", ans); ans = (x > 5) || (x > 15); Console.WriteLine("x > 5 || x > 15 = {0}", ans); ans = (x == 5) || (x < 0); Console.WriteLine("x == 5 || x < 0 = {0}", ans); ans = (x == 5) ^ (x > 0); Console.WriteLine("x == 5 ^ x > 0 = {0}", ans); ans = (x == 10) ^ (x > 0); Console.WriteLine("x == 10 ^ x > 0 = {0}", ans); ans = !(x > 10); Console.WriteLine("!(x > 10) = {0}", ans); }
Lines 10 and 13 show the && operator. x = 10. So, x>5 = true (as 10 > 5). x < 15 = true (as 10<15) (x > 5) && (x < 15) = true && true = true On the other hand, x > 5 && x > 15 = true && false = false However, Line 16 shows the same two conditions with || operator. x > 5 || x > 15 = true || false = true Line 19 also uses the || operator. This time round, x == 5 is false, since x = 10, and 10 ≠5. Also, x < 0 is false, since 10 > 0. Thus, x == 5 || x<0 = false || false = false. Lines 22 and 25 show how the exor ^ operator works. In case of line 22, x == 5 is false, x>0 is true and false ^ true = true. In case of line 25, x == 10 is true, x>0 is true and true ^ true = false. Line 27 shows the use of ! operator. Since x > 10 is false (as 10 ≤ 10), !(x>10) must be true. Upon running the above program, we get the following output. 30 | P a g e
Learn C# - do it yourself way...
2.14 Bitwise Logical Operators
31 | P a g e
2008
Learn C# - do it yourself way...
2008
6 Polymorphism, Constructors and Destructors 6.1 Function Overloading There are 6 different versions of the Multiply() method in the Test class. st
The 1 version multiplies two ints and returns an int as the answer. The 2
nd
class Test { public int Multiply(int a, int b) { return a * b; }
version accepts 2 doubles as
public double Multiply(double a, double b) { return a * b; }
input parameters and returns a double result as the answer. The 3
rd
version accepts an integer and a double number as an argument, and
public double Multiply(int a, double b) { return a * b; }
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.
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);
32 | 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 33 | 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 34 | 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 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.
class Date { public int day; public int month; public int year; public static Date operator +(Date d1, Date d2) { Date result = new Date();
The two Date objects are passed as
result.day = d1.day + d2.day; result.month = d1.month + d2.month; result.year = d1.year + d2.year;
arguments into d1 and d2. To store the sum of Date objects, we take a result Date object. We set the day,
if(result.day>30){ result.day -= 30; result.month++; }
month and year of the result Date object as the sum of the corresponding day, month and year of d1 and d2.
if (result.month > 12) { result.month -= 12; result.year++; }
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
return result; }
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,
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;
months and years can be tricky, so a
if (days1 < days2) ans = true; else ans = false; return ans;
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
35 | P a g e
public static bool operator >(Date d1, Date d2)
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("Day : " + day); Console.WriteLine("Month : " + month); Console.WriteLine("Year : " + year); 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("d1 > d2 : " + ans); } }
Suppose we write the nstruction 2 + 3.
36 | P a g e
2008
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 -
37 | 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; }
38 | 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); }
39 | P a g e
Learn C# - do it yourself way...
2008
public void Volume() { Console.WriteLine("Volume : " + width * height * depth); } } class BoxDemo { public static void Main() { Box myBox1 = new Box(); Box myBox2 = new Box(5); Box myBox3 = new Box(10, 20, 30); myBox1.GetBox(); myBox2.GetBox(); myBox3.GetBox(); myBox1.Volume(); myBox2.Volume(); myBox3.Volume(); } }
A constructor is a spe ial method that is called automat ically, when an object is created.
Why Constr ctors? When we first create an object, all its fields are initialis d to 0. In other words, the mem ry is zeroed out.
Box myBox; myBox = new Box();
To be able to use this ox object, we must put in meani gful values in the width, height and epth of myBox. Thus, we must a sign values to myBox’s instance variables. To do so, we must ma ually go in and initialise all the f elds of the myBox object. 40 | P a g e
Learn C# - do it yourself way...
2008
myBox.width = 10; myBox.height = 20; myBox.depth = 30; All of this seems rosy-rosy till we have to work with jus t 1 Box object. But, consider a real-time shipping application, w here we to keep track of thousan s of orders and consignments. Ea h consignment is shippe in Box object. So, if we typicall y have 1000 Box objects; myBox1, myBox2, myBox3,... this proces of manually initialising all the fiel s becomes very tedious and cum ersome.
Well, you can use con enience methods like SetBox(). ut, when you have a thousand objec s, you have explicitly call/invoke SetBox() method on each Box o bject. Once again, it calls for a lo of work.
How can Co structors help me?
41 | 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 donothing constructor.
42 | 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 automatically, just before the objects of this class are destroyed des troyed by GC. There are two ways to write a destructor – class MyClass { ~MyClass() { Console.WriteLine( Console .WriteLine("You "You can free up an unmanaged resources here."); } }
43 | P a g e
Learn C# - do it yourself way...
2008
class DestroyDemo { public static void Main() { MyClass obj = new MyClass MyClass(); (); obj = null 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( Console .WriteLine("You "You can free up any unmanaged resources here"); here" ); } finally { base.Finalize(); base .Finalize(); } } }
Now, when you have a number of objects, how does GC keep track of which objects to finalize? The GC maintains a queue of all the objects that are to be finalized. This is called Finalization Queue. However, we never know for sure, when the GC kicks in and calls the finalizer(destructor) method. If there is an unmanaged resource that needs to be released promptly on time, this approach is not helpful. 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 Explicit Resource Cleanup 44 | P a g e
Destructor or Finalize() method Dispose()
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 a m 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 diff erent Employee objects.
45 | P a g e
Learn C# - do it yourself way...
2008
But, Kathy questions herself, does every Employee have a salary? Is it true that every Employee object has a salary. By studying the problem 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 f ield 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; } }
46 | P a g e
Learn C# - do it yourself way...
2008
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 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/subclass. 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. 47 | P a g e
Learn C# - do it yourself way...
Salary Employee and
2008
ourly Employee are both emplo ees.
When you have two classes which are more specific cases of something more general, you can set them up to inherit rom the same base class. Employee name address SSN number GetEmployee()
Salary salary
Hourly hourlyRate hoursWorke d
computePay() computePay()
Build up your class mode , by starting General and getting mor e Specific
7.2 Method verriding class Employee { public string name; public string address; public int SSN; public int number;
48 | P a g e
Learn C# - do it yourself way...
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;
49 | P a g e
2008
Learn C# - do it yourself way... 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.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(); } }
50 | P a g e
2008
Learn C# - do it yourself way...
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;
51 | P a g e
2008
Learn C# - do it yourself way... public int SSN; 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(); } }
52 | P a g e
2008
Learn C# - do it yourself way...
2008
7.5 Calling Parent class Constructors 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() {
53 | P a g e
Learn C# - do it yourself way...
2008
Salary s = new Salary("Jane Smith", "222 Oak Drive", 111009999, 3, 10000); s.GetEmployee(); } }
54 | 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; a = new Animal();
55 | P a g e
Learn C# - do it yourself way...
2008
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() { } } class TwoDimShape : Shape { public int a;
56 | P a g e
Learn C# - do it yourself way... 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); } public void SetBox(int x, int y, int z)
57 | P a g e
2008
Learn C# - do it yourself way... { 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 } } }
58 | P a g e
2008
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.
59 | 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 60 | 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 –
61 | 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,
62 | 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 . 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;
63 | 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).
64 | P a g e
Learn C# - do it yourself way...
2008
8.9 Skeleton of a C# Executable Assembly MyProgram.exe
File1.c
File2.cs
File3.cs
namespace A { .... }
namespace B { .... }
namespace C { .... }
class A { //Body of cla s }
class B { //Body of class }
class C { //Body of class }
8.10 Interfaces An interface is a colle tion of abstract members. A clas implements an interface thereby inheriting the abstract methods of t e interface. All the methods of an interface need to be defined in th class. Syntactically, an inter ace is defined using the C# interf ce keyword. public interface IName { void method1(); void method2(); }
In the .NET Framewo k, interfaces have a special nami g convention. All interface names begin with a capital I. Interfaces can have pr perties as well. Difference from a class – 1. You cannot create an object of an interface. 65 | 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; }
66 | 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 payrelated 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 –
67 | 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 68 | 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()); } }
69 | P a g e
Learn C# - do it yourself way...
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"); } }
70 | P a g e
2008
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.
71 | P a g e
Learn C# - do it yourself way...
To create a FileStrea FileStream class.
2008
in C#, we must create an object f the
FileStream fs = new F leStream(,,,) The FileStream constr ctor 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, w ich mode you would like to operate the file in. The FileMode enum l oks like this – enum FileMode{ CreateNew, Create, Open, OpenOrCreate, Truncate, Append } Create always creates a new file. CreateNew create a ne w file, and if the file already exists, it overwrites the old file. OpenOr Create works in 2 ways – if the file oes not exist, it creates the file, i the file exists
72 | 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 of 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();
73 | 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.
74 | 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() {
75 | 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 th 10. After the second call to Seek(), the cursor would reach 10+2=12 position.
76 | 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); } }
77 | 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 subdirectory. 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); } } }
78 | P a g e
Learn C# - do it yourself way...
79 | P a g e
2008