0% found this document useful (0 votes)
3 views

C#.NET-UNIT2

This document provides an overview of C# fundamentals, focusing on the structure of basic C# classes, the Main() method, object creation, constructors, variable initialization, and input/output operations using the Console class. It explains the importance of constructors, the distinction between classes and objects, and how to manipulate arrays in C#. Additionally, it covers the differences between rectangular and jagged arrays, as well as the methods available in the System.Array base class.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

C#.NET-UNIT2

This document provides an overview of C# fundamentals, focusing on the structure of basic C# classes, the Main() method, object creation, constructors, variable initialization, and input/output operations using the Console class. It explains the importance of constructors, the distinction between classes and objects, and how to manipulate arrays in C#. Additionally, it covers the differences between rectangular and jagged arrays, as well as the methods available in the System.Array base class.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

UNIT-2

C# FUNDAMENTALS

The Anatomy of basic C# class:


• In C#, all program logic must be contained within a type definition (type may be a member of the set {class,
interface, structure, enumeration, delegate}).
• Unlike C or C++, in C# it is not possible to cr eate global functions or global points of data.
• In its simplest form, a C# program can be written as follows:

Program 3.1 Test.cs

using System;
class Test
{
public static int Main(string[] args)
{
Console.WriteLine("Hello World!");
return 0;
}
}
• Every executable C# application must contain a class defining a Main() method, which is used to signify the entry
point of the application.
• Main() is used with the public and static keywords.
• The public members are accessible from other types, while static members are scoped at the class level (rather
than the object level) and can thus be invoked without the need to first create a new class instance (or object).
• In addition to the public and static keywords, this Main() method has a single parameter, which is an array of
strings (string[] args).
• This parameter may contain any number of incoming command-line arguments.

• The program Test.cs makes use of the Console class, which is defined within the System namespace.

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 1


• WriteLine() is a static member(Method) of Console class, which is used to pump a text string to the standard
output.

NOTE: We can use Console.ReadLine() to ensure the command prompt launched by Visual Studio 2005 remains
visible during a debugging session until we press the Enter key.

Variations on the Main() Method:


The Main() function can be take any of the following forms based on our requirement:

// No return type, array of strings as argument. public


static void Main(string[] args )
{
//some code
}

// No return type, no arguments. public


static void Main()
{
//some code
}
// Integer return type, no arguments. public
static int Main()
{
//some code
//return a value to OS
}

NOTE: The Main() method may also be defined as private. Doing so ensures other assemblies cannot directly
invoke an application’s entry point. Visual Studio 2005 automatically defines a program’s Main() method as
private. Obviously, your choice of how to construct Main() will be based on two questions. First, do you need
to process any user-supplied command-line parameters? If so, they will be stored in the array of strings.
Second, do you want to return a value to the system when Main() has completed? If so, you need to return
an integer data type rather than void.

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 2


Creating Objects: Constructor Basics
• All object-oriented (OO) languages make a clear distinction between classes and objects.
• A class is a definition (or, if you will, a blueprint) for a user-defined type (UDT).
• An object is simply a term describing a given instance of a particular class in memory.
• In C#, the new keyword is used to create an object.
• Unlike other OO languages (such as C++), it is not possible to allocate a class type on the stack; therefore,
if you attempt to use a class variable that has not been “new-ed,” you are issued a compile-time error.
Thus the following C# code is illegal:

using System;
class Test
{
public static int Main(string[] args)
{
Test c1;
c1.SomeMethod(); //error!! Must use “new”
...
}
}

Object creation:
To illustrate the proper procedures for object creation, consider the following code:

using System;
class Test

{
public static int Main(string[] args)
{
/ / You can declare and create a new object in a single line...
Test c1 = new Test();
/ / ...or break declaration and creation into two lines.
Test c2;

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 3


c2 = new Test(); ...
}
}

• The new keyword will calculate the correct number of bytes for the specified object and acquires sufficient
memory from the managed heap.
• Here, we have allocated two objects c1 and c2, each of which points to a unique instance of Test type.
Note that C# object variables are really a reference to the object in memory, not the actual object itself.
• Thus, c1 and c2 each reference a distinct Test object allocated on the managed heap.

• In the previous program, the objects have been constructed using the default constructor, which by
definition never takes arguments.

• Every C# class is automatically provided with a free default constructor, which you may redefine if needed.

• The default constructor ensures that all member data is set to an appropriate default value. But in C++,
un-initialized data gets garbage value.

Usually, classes provide additional constructors also. Using this, we can initialize the object variables at the time
of object creation. Like in Java and C++, in C# constructors are name

identically to the class they are constructing, and they never provide a return value (not even void).

Consider the following example –

Program 3.3
using System;
class Test
{
public string userMessage;

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 4


/ / Default constructor. public Test()
{
Console.WriteLine("Default constructor called!");
}

public Test (string msg)


{
Console.WriteLine("Parameterized constructor called!");

userMessage = msg;
}

public static int Main(string[] args)


{
/ / Call default constructor.
Test c1 = new Test ();
Console.WriteLine("Value of userMessage: {0} \n", c1.userMessage);

/ / Call parameterized constructor.


Test c2;
c2 = new Test ("Hello World");
Console.WriteLine("Value of userMessage: {0}", c2.userMessage); Console.ReadLine(); return 0;
}
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 5


NOTE:
1. Technically speaking, when a type defines identically named members (including constructors) that
differ only in the number of—or type of—parameters, the member in question is overloaded.

2. As soon as we define a custom constructor for a class type, the free default constructor is removed. If
we want to create an object using the default constructor, we need to explicitly redefine it as in the
preceding example.

Default Assignments and Variable Scope


All intrinsic .NET data types have a default value. When we create custom types, all member variables are
automatically assigned to their respective default values. Consider an example –

Program 3.5
class Test
{
public int a; //default value is 0
public byte b; //default value is 0
public char c; //default value is null
public string s; //default value is nu ll
public static void Main()
{
Test t=new Test();
Console.WriteLine(“{0}, {1}, {2}, {3}”, a, b, c, s);
}
}

All the variables will be initialized to their default values when we start debugging. However, we can not
expect the same within method scope. For example, the following program will generate an error.
class Test
{
public static void Main()
{
int a; //need to assign some value to ‘a’
Console.WriteLine(“{0}”, a); //Error: Unassigned local variable ‘a’
}
}

NOTE: There is an exception for the mandatory assignment of a local variable. If the local variable is used as
an output parameter, then it need not be initialized before use. However, note that, they are used to receive
the value from a function.

The C# Member Variable Initialization Syntax


Consider a class (or any other type) having more than one constructor with different set (may be different in
type or number) of arguments. Now, if any member variable needs to be initialized with same value in all
the situations, we need to write the code repeatedly in all the constructors. For example

class Test {
private int a;

Test()
{ a=5;
}

Test(int k)
{
a=5; …….
}

Test(string s)
{
a=5; …….
}
}

Though the above code is valid, there is redundancy in code. We can write a function for such initialization
like –

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 7


class Test
{
private int a;

public void init()


{
} a=5;

Test()
{
init();
}

Test(int k)
{ init()

…….
}

Test(string s)
{
init()
…….
}
}

Here we have function call instead of assignment. Thus, redundancy still exists. To avoid such situation, C#
provides the initialization of member variables directly within a class as shown –

class Test {
private int a =5; private
string s= “Hello”;
…………..
}

This facility was not available in C++. Note that, such an initialization will happen before the constructor gets
called. Hence, if we provide any other value to a variable through constructor, the previous member
assignment will be overwritten.

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 8


Basic Input and Output with the Console Class
In many of the programs what we have seen till now, made use of System.Console class. As the name
suggests, Console class is defined in System namespace and it encapsulates input, output and error stream
manipulations. This class is widely used for console applications but not for Windows or Web applications.

There are four important static methods in Console class:


• Read() Used to capture a single character from the input stream.
• ReadLine() Used to receive information from the input stream until the enter key is pressed.
• Write() This method pumps text to the output stream without carriage return (enter key)
• WriteLine() This pumps a text string including carriage return to the output stream.

Following table gives some important member of Console class:

Member Meaning
BackgroundColor These properties set the background/foreground colors for the
ForegroundColor current output. They may be assigned any member of the
ConsoleColor enumeration.
BufferHeight These properties control the height/width of the console’s buffer
BufferWidth area.
Clear() This method clears the buffer and console display area.
Title This property sets the title of the current console.
WindowHeight These properties control the dimensions of the console in relation
WindowWidth to the established buffer.
WindowTop
WindowLeft

To illustrate the working of Console class methods, consider the following example –

Program 3.6
using System;
class BasicIO
{
public static void Main()
{

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 9


Console.Write("Enter your name: ");
string s = Console.ReadLine();
Console.WriteLine("Hello, {0} ", s);
Console.Write("Enter your age: "); s
= Console.ReadLine();
Console.WriteLine("You are {0} years old", s);
}
}

The output would be – Enter


your name: Ramu
Hello, Ramu
Enter your age: 25
You are 25 years old

Array Manipulation in C#
• C# arrays look like that of C/C++.
• But basically, they are derived from the base class viz. System.Array.
• Array is a collection of data elements of same type, which are accessed using numerical index.
Normally, in C#, the array index starts with 0.
• But it is possible to have an array with arbitrary lower bound using the static method CreateInstance()
of System.Array.
• Arrays can be single or multi-dimensional. The declaration of array would look like –

int[ ] a= new int[10];


a[0]= 5; a[1]= 14;
……….
string[ ] s= new string[2]{“Ramu”, “Shymu”}; int[ ]
b={15, 25, 31, 78}; //new is missing. Still valid

In .NET, the members of array are automatically set to their respective default value. For example, in the
statement, int[ ] a= new int[10];
all the elements of a are set to 0. Similarly, string array elements are set to null and so on.

Array as Parameters and Return Values


Array can be passed as parameter to a method and also can be returned from a method. Consider the
following example –

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 10


Program 3.31

using System;
class Test
{
public static void disp(int[] arr) //taking array as parameter
{
for(int i=0;i<arr.Length;i++)
Console.WriteLine("{0} ", arr[i]);

public static string[] MyFun() //returning an array


{
string[] str={"Hello", "World"};
return str;
}
public static void Main() {
int[] p=new int[]{20, 54, 12, -56};
disp(p);
string[] strs=MyFun();
foreach(string s in strs)
Console.WriteLine(s);
}
}

The output would be – 20 54 12 -56 Hello World

Working with Multidimensional Arrays


There are two types of multi-dimensional arrays in C# viz. rectangular array and jagged array.

1. Rectangular array:
The rectangular array is an array of multiple dimensions and each row is of same length. For example

Program 3.32
using System; class
Test

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 11


{
public static void Main()
{
int[,] arr=new int[2,3]{{5 , 7, 0}, {3, 1,
8}}; int sum=0; for(int i=0;i<2; i++)
for(intj=0;j<3;j++)
sum=sum+arr[i,j];

Console.WriteLine("Sum is {0}", sum);

}
}

The output would be – Sum


is 24
2. Jagged array: contain some number of inner arrays, each of which may have unique size. For example
– Program 3.33

using System;
class J aggedArray
{

public static int[][] JArr=new int[3][];

public static void Main()


{
int m, n, p, sum=0;

Console.WriteLine("Enter the sizes for 3 inner arrays:");


m=int.Parse((Console.ReadLine()).ToString());
n=int.Parse((Console.ReadLine()).ToString());
p=int.Parse((Console.ReadLine()).ToString());

J Arr[0]=new int[m]; J Arr[1]=new


int[n]; J Arr[2]=new int[p];

Console.WriteLine("Enter the elements for array:"); for(int i=0;i<3;i++)


for(int j=0;j<J Arr[i].Length;j++)
{
J Arr[i][j]=int.Parse((Console.ReadLine()).ToString());
sum=sum+J Arr[i][j];

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 12


}

Console.WriteLine(" \nThe Sum is: {0}",sum);


}
}

The output would be –


Enter the sizes for 3 inner ar rays:
2 3 2
Enter the elements for array:
1 2 3 4 5 6 7
The Sum is: 28

The System.Array Base Class


Every array in C# is derived from the class System.Array. This class defines number of methods to work with
arrays. Few of the methods are given below –

Member Meaning
BinarySearch() This static method searches a (previously sorted) array for a given item.
If the array is composed of user-defined data types, the type in question must
implement the IComparer interface to engage in a binary search.

Clear() This static method sets a range of elements in the array to empty values (0 for
value types; null for reference types).

CopyTo() This method is used to copy elements from the source array into the destination
array.

Length This read-only property is used to determine the number of elements in an array.

Rank This property returns the number of dimensions of the current array.

Reverse() This static method reverses the contents of a one-dimensional array.

Sort() This method sorts a one-dimensional array of intrinsic types. If the elements in
the array implement the IComparer interface, we can also sort an array of
userdefined data type .

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 13


Consider the following example to illustrate some methods and/or properties of System.Array class –
Program 3.34

using System; class

Test
{
public static void Main()

{
int[] arr=new int[5]{12, 0, 45, 32, 67};

Console.WriteLine("Array elements are :"); for(int

i=0;i<arr.Length;i++)
Console.WriteLine("{0} \t", arr[i]);

Array.Reverse(arr);

Console.WriteLine("Reversed Array elements are :"); for(int


i=0;i<arr.Length;i++)
Console.WriteLine("{0} \t", arr[i]);

Array.Clear(arr, 1, 3);

Console.WriteLine("Cleared some elements :"); for(int i=0;i<arr.Length;i++)


Console.WriteLine("{0} \t", arr[i]);
}
}

The Output would be – Array


elements are:
12 0 45 32 67
Reversed Array elements are:
67 32 45 0 12
Cleared some elements:
67 0 0 0 12
String Manipulation in C#
Till now, we have used string key word as a data type. But truly speaking, string is an alias type for
System.String class. This class provides a set of methods to work on strings. Following is a list of few such
methods –

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 14


Member Meaning
Length This property returns the length of the current string.

Contains() This method is used to determine if the current string object contains a
specified string.
Concat() This static method of the String class returns a new string that is composed of
two
discrete strings.

CompareTo() Compares two strings.

Copy() Returns a fresh new copy of an existing string.

Format() This static method is used to format a string literal using other primitives (i.e., numerical
data and other strings) and the {0} notation examined earlier in this chapter.

Insert() This method is used to receive a copy of the current string that contains newly inserted
string data.

PadLeft() These methods return copies of the current string that has been padded with specific
PadRight() data.

Remove() Use these methods to receive a copy of a string, with modifications (characters
Replace() removed or replaced).

Substring() This method returns a string that represents a substring of the current string.

ToCharArray() This method returns a character array representing the current string.

ToUpper() These methods create a copy of a given string in uppercase or lowercase.


ToLower()

Consider the following example –

Program 3.35

using System; class

Test
{
public static void Main()

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 15


{
System.String s1="This is a string"; string s2="This
is another string";

if(s1==s2)
Console.WriteLine("Same strings");
else
Console.WriteLine("Different strings"); string
s3=s1+s2;

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 16


Console.WriteLine("s3={0}",s3);

for(int i=0;i<s1.Length;i++)

Console.WriteLine("Char {0} is {1} \n",i, s1[i]);

Console.Wr iteLine("Cotains 'is'?: {0}", s1.Contains("is"));

Console.WriteLine(s1.Replace('a',' '));
}
}

The output would be – Different


strings
s3=This is a string This is another string
Char 0 is T Char 1 is h Char 2 is i Char 3 is s Char 4 is Char 5 is i Char 6 is s Char 7 is
Char 8 is a Char 9 is Char 10 is s Char 11 is t Char 12 is r
Char 13 is I Char 14 is n Char 15 is g

Cotains 'is'?: True

This is string

Encapsulation services:
C# Encapsulation:

• Encapsulation is the concept of wrapping data into a single unit.


• It collects data members and member functions into a single unit called class.
• The purpose of encapsulation is to prevent alteration of data from outside.
• This data can only be accessed by getter functions of the class.
• A fully encapsulated class has getter and setter functions that are used to read and write data.
• This class does not allow data access directly

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 17


As in encapsulation, the data in a class is hidden from other classes, so it is also known as data-hiding.
The following are the benefits of encapsulation:

• Protection of data from accidental corruption

• Specification of the accessibility of each of the members of a class to the code outside the class

• Flexibility and extensibility of the code and reduction in complexity

• Lower coupling between objects and hence improvement in code maintainability


Encapsulation in C# using the following access modifiers:

• Public: Access to all code in the program


• Private: Access to only members of the same class
• Protected: Access to members of same class and its derived classes
• Internal: Access to current assembly
• Protected Internal: Access to current assembly and types derived from containing class

The First Pillar: C#’s Encapsulation Services


The concept of encapsulation says that the object’s data should not be directly accessible from a method. If
the data is to be manipulated, it has to be done indirectly using accessor (get) and mutator(set) method. C#
provides following two techniques to manipulate private data members –

• Define a pair of traditional accessor and mutator methods


• Defined a named property.

It is good programming practice to make all the data members or fields of a class as private. This kind of
programming is known as black box programming.

Enforcing Encapsulation Using Traditional Accessors and Mutators


If we want to access any private data, we can write a traditional accessor (get method) and when we want to
provide value to data, we can write a mutator (set method). For example,

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 18


class Emp
{
string Name;
public string GetName() //accessor
{ return Name;
}

public void SetName(string n) //mutator


{
Name=n;
}
}
class Test
{
public static void Main()
{
Emp p=new Emp(); p.SetName(“Ramu”);
Console.WriteLine(“{0}”,p.GetName());
}
}

In this example, using the public methods, we could able access private data.

Another Form of Encapsulation: Class Properties


Apart from traditional accessors and mutators, we can make use of properties provided by .NET class (and
structures, interfaces). Properties resolve to a pair of hidden internal methods. The user need not call two
separate methods to get and set the data. Instead, user is able to call what appears to be a single named
field. For illustration, consider the following example –

public string EmpName // EmpName is name of the property


get
{
// Name is field-name
return Name;
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 19


set
{ // value is a keyword
Name=value;

}
class Test
{
public static void Main()
{
Emp p=new Emp();
p.EmpName="Ramu";

//use name of the property

Console.WriteLine("{0}",p.EmpNam);
}
}

A C# property is composed using a get block (accessor) and set block (mutator). The value keyword
represents the right-hand side of the assignment. Though, value is an object, the underlying type of the
object depends on which kind of data it represents. For example, in the previous program, the property
EmpName is operating on a private string, which maps to System.String. Unlike traditional accessors and
mutators, the properties make our types easier to manipulate.

Properties are able to respond to the intrinsic operators in C#. For example,

using System; class


Emp
{

int Sal;

public int Salary


{
get
{
return Sal;

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 20


}
set Sal=value;
{

}
}
}

class Test
{
public static void Main()
{
Emp p=new Emp();
p.Salary=12000; p.Salary++;
Console.Wr iteLine("{0}",p.Sa
lary);

//12001 p.Salary
-=400;
Console.WriteLine("{0}",p.Salary)

//11601
}
}

Read-only and Write-only Properties


In some of the situations, we just want to set a value to a data member and don’t want to return it. In such
a situation, we can omit get block. A property with only a set block is known as write-only property. In the

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 21


same manner, we can just have a get block and omit set block. A property with only a get block is known as
read-only property. For example,

class Emp
{
string SSN, name; int EmpID;

public Emp(string n, int id)


{
name=n;
EmpID=id;
}
public string EmpSSN //read-only property
{ get{ return SSN;}
}
}

Understanding static properties


C# supports static properties. Note that, static members of a class are bound to class but not for objects.
That is, to access static members, we need not create an object of the class. The same rule will apply to
static properties too. For example,

class Emp
{
static string CompanyName;

public static string Company


{
get{ return CompanyName; } set{
CompanyName=value; }
}

public static void Main()


{
Emp.Company=“RNSIT”; //use class name
Console.WriteLine(“We are at {0}”, Emp.Company);
}
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 22


The Second Pillar: C#’s Inheritance Supports
Inheritance facilitates code reuse. The inheritance can be either classical inheritance (is-a relationship) or
containment/delegation model (has-a relationship).

When we establish is-a relationship between classes, we are building a dependency between types. The
basic idea of classical inheritance is that new classes may influence and extend the functionality of other
classes. The hierarchy may look something like –

Employee

Manager

SalesMan
Now we can say that, Manager is-a Employee and SalesMan is-a Employee.

In classical inheritance, the base classes are used to define general characteristics that are common to all
derived classes. The derived classes extend this general functionality while adding more specific behaviors
to the class.

Consider an example –

public class Emp


{
protected string Name;
protected int EmpID;
…………..
}

public class SalesMan:Emp //SalesMan is inherited from Emp


{
int number_of_sales; // also includes members Name, EmpID ………..
}

class Test
{
public static void Main()

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 23


{
Emp e=new Emp();
SalesMan s=new SalesMan();

}
}

Controlling Base-Class Creation


Usually, the base class constructors are used to initialize the members of base class. When derived class
has few more members and if we need to initialize, then we will write constructor for derived class. In
such a situation, there is a repetition of code. For example –

public class Emp


{
protected string Name; protected
int EmpID;

public Emp(string n, int eid, float s)


{
Name=n; EmpId=eid;

}
}

public class SalesMan:Emp


{
int number_of_sales;

public SalesMan(string n, int eid, int s)


{
Name=n; / / co de repeated EmpId=eid; / / code
repeated
number_of_sales=s;
}
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 24


If there is more number of data fields in the base class, then in each of the derived class constructors, we
need to repeat such assignment statements. To avoid this, C# provides an option to explicitly call base class
constructors as shown below –

public class Emp


{
protected string Name; protected
int EmpID;

public Emp(string n, int eid)


{
Name=n;
EmpId=eid;
}
}

public class SalesMan:Emp


{
int bonus;
public SalesMan(strin g n, int eid, int b): base(n, eid)
{
bonus=b; //other members are passed to base class to initialize
}
}

class Test
{

public static void Main()


{
Emp e1=new Emp(“Ram”, 25);
SalesMan s1= new SalesMan(“Sham”, 12, 10);

}
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 25


Multiple Base Classes
Deriving a class from more than one base class is not possible in C#. That is, multiple inheritance is not
supported by C#. When we need to use the properties of more than one class in a derived class, we need to
write interfaces rather than classes. Then we can implement any number of interfaces to achieve code
reusability.

Keeping Family Secrets: The protected Keyword


The private members of a class can not be available to derived classes. So, we will go for protected keeping
the privacy of the data. The protected members of a class can not be accessed from outside, but still be
available to derived classes.

Preventing Inheritance: Sealed Classes


In some of the situations, we may don’t want our class to be inherited by any other class. For example –
Employee

SalesMan

Part-time SalesMan

Here, a class called Part-time SalesMan is derived from SalesMan class which in-turn is derived from
Employee class as shown in the diagram. Now, we don’t want any more classes to be derived from Part-time
SalesMan class. To prevent such inheritance, C# provides a keyword sealed. The usage is depicted hereunder:

public sealed class Part_TimeSalesMan: SalesMan


{
//body of Part_TimeSalesMan class

Now any attempt made to derive a class from Part_TimeSalesMan class will generate an error:
public class Test: Part_TimeSalesMan //compile -time error!!!
{
…………..
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 26


Many of the inbuilt classes of C# are sealed classes. One such example is System.String.

Programming for Containment/Delegation


Till now we have discussed is-a relationship. Now we will see, how to write program for has-a relationship.
Consider a class Radio –

class Radio
{
public void TurnOn(bool on)
{ if(on)
Console.WriteLine(“Radio is on”); Console.WriteLine(“Radio is
else
off”);
}
}

Now, consider a class Car –

class Car
{
int CurrSpeed, MaxSpeed; string
name;
bool carIsDead=false;

public Car() { MaxSpeed=100} public


Car(string n, int m, int c)
{
name=n; MaxSpeed=m;
CurrSpeed=c;
}
public void SpeedUp(int a)
{
if(carIsDead)

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 27


Console.WriteLine(“Out of order”);
else

{
CurrSpeed+=a;
}
}
}

Now, we have two classes viz. Radio and Car. But, we can not say, “Car is a Radio” or “Radio is a Car”. Rather,
we can say, “Car has a Radio”. Now, the Car is called containing Class and Radio is called contained class.

To make the contained class to work, we need to re-define Car class as –

class Car
{ ………..
private Radio rd=new Radio();
}

To expose the functionality of the inner class to the outside world requires delegation. Delegation is the act
of adding members to the containing class that make use of the functionality of contained class.

class Car
{ ……….
public void Tune(bool s)
{
rd.TurnOn(s); //delegate request to inner object
}
}

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 28


To make this function work, in the Main() function we can write – Car c=new Car(); c.Tune(false);

Thus by making one class to be a member of other class, we can establish has-a relationship. But it is always
the job of outer class to define a member function which activates the inner class objects.

The Third Pillar: C#’s Polymorphic Support


Polymorphism answers the question “how to make related objects respond differently to the same request?”
Consider the following example to illustrate the need of polymorphism.

Assume we have a base class Employee and two derived classes Manager and SalesMan.

class Employee
{
…….
public void Bonus(float b)
{ basicSal+=b;
}
}
class Manager:Employee
{
………..
}
class SalesMan: Employee
{
…………
}

Now, the classes Manager and SalesMan both contains the method Bonus(float). Thus in the Main() function,
we can call Bonus() through the objects of Manger and SalesMan –

Manager m=new Manager();


m.Bonus(500);

SalesMan s=new SalesMan() s.Bonus(300);

Obviously, the Bonus() method works same for both the objects. But in reality, the bonus for a SalesMan
should be calculated based on number of sales. Manager can be given bonus based on his other performance

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 29


like successful completion and delivery of a project etc. This means, we need a Bonus() method which works
differently in two derived classes.

The polymorphic technique of C# provides solution for this problem. With the help of virtual and override
keywords, we can make same function to behave differently in base-class and all the derived classes. For
example,

class Employee
{

public virtual void Bonus(float b)


{ basicSal+=b;
}
}

class SalesMan:Employee
{

public override void Bonus(float b)


{
int salesBonus=0;

if(numOfSales<=100)
salesBonus=10; elseif
(numOfSales<=200)
salesBonus=20;

base.Bonus(b*salesBonus); //making use of base class method


}
}

class Test
{
public static void Main()
{
Employee e=new Employee() ;
e.Bonus(100); //base class Bonus() is called

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 30


SalesMan s=new SalesMan()
s.Bonus(300); //derived class Bonus() is called
}
}

We can see that when the Bonus() method is invoked through base class object, the corresponding method
will be called. Whereas, when Bonus() is invoked with the object s of derived class, the overridden method
Bonus() will be called.

NOTE that any overridden method is free to call its corresponding base class method using the keyword
base. Thus, the overridden method can have its own statements and also can make use of the behaviors of
base class virtual method also.

Defining Abstract Classes


Sometimes, the creation of base class objects will not be of any use. For example, an Employee is always
identified with a designation. Thus, an employee must be either a Manager or a SalesMan or working at
some such other designation. So, creation of the object of class Employee is useless. In such situations, we
can prevent base class instantiation by making it as abstract.

public abstract class Employee


{
………
}
Employee e=new Employee //error !!

Thus, abstract class is a class which just declares members (data and method) and no object can be created
for this class. The member methods of abstract class may be used by the objects of derived class either
directly or by overriding them in the derived class.

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 31


Enforcing Polymorphic Activity: Abstract Methods
An abstract class may contain the definition for methods it is defining. The derived classes are free to use
such methods directly or they can override and then use. But in some situations, the definitions of abstract
base-class methods may not be useful. The derived classes only should define the required behavior. In this
case, we need to force the derived classes to override the base class methods. This is achieved using abstract
methods.

An abstract class can define any number of abstract methods, which will not supply any default
implementation. Abstract method is equivalent to pure virtual functions of C++. The abstract methods can
be used whenever we wish to define a method that does not supply a default implementation. To understand
the need for abstract methods, consider the following situation:

Object virtual void Draw()

Shape

Draw()
Hexagon

Circle Draw()

Here, each derived class like Hexagon and Circle of Shape has to override Draw() method to
indicate the methodology of drawing itself. If any derived class forgets to override Draw() method, the code
may look like –

abstract class Shape


{
public virtual void Draw()
{
Console.WriteLine(“Shape.Draw()”);
}
}
public class Circle:Shape()
{ public Circle();

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 32


public class Hexagon:Shape()
{
………….. public override
void Draw()
{
Console.WriteLine(“Hexagon.Draw()”);
}
}

public class Test


{
public static void Main()
{
Circle c= new Circle( );
c.Draw(); //Draw() method of Shape class is called

Hexagon h=new Hexagon();


h.Draw(); //Draw() method of Hexagon class is called
}
}

In this example, the Circle class is not overriding the Draw() method. So, when the Draw() method is invoked
through the object of Circle class, the Draw() method of Shape class itself will be called. Obviously, the Draw()
method of Shape class will not be having any information about how to draw a circle and hence it will be
meaningless. This shows that virtual methods of base class need not be overridden by derived classes.

When programmer must be forced to override Draw() method, the method of base class must be made
abstract –

abstract class Shape


{

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 33


// completely abstract method. Note the semicolon at the end public abstract void
Draw();

public class Circle:Shape()


{
public override void Draw() //has to override
{
Console.WriteLine(“Circle.Draw()”);
}
}
public class Hexagon:Shape()
{ …………..
public override void Draw() //has to override
{
Console.WriteLine(“Hexagon.Draw()”);
}
}

public class Test


{
public static void Main()
{
Circle c= new Circle();

c.Draw(); //Draw() method of Circle class is called

Hexagon h=new Hexagon();


h.Draw(); //Draw() method of Hexagon class is called
}
}

Thus, by making a base class method as abstract, we are making use of run-time polymorphism or late
binding. That is, the binding between the object and the method to be invoked is decided only at runtime.
This concept is more clear when we re-design our Main() function in the following format:

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 34


public static void Main()
{
Shape[ ] s={new Circle(), new Hexagon()};

for(int i=0;i<s.Length;i++) s[i].Draw();

}
This may seems to be quite interesting. Till now, we have heard that we can not create objects for abstract
classes. But in the above code snippet, we are creating array of objects of base-classes. How? This is very
obvious as array of objects stores references to variables but not the objects directly. Thus, in the above
example, s[0] stores reference to the object of type Circle and s[1] stores reference to the object of type
Hexagon.

In the for loop, when we use the statement – s[i].Draw();


the content (i.e. whether reference to Circle or reference to Hexagon) of s[i] is considered to decide which
Draw() method to be invoked and the type (i.e. here type is Shape) of s[i] is ignored. This is nothing but runtime
polymorphism or late binding.

NOTE (Very important):


After dealing with entire story about abstract classes and abstract methods, somebody may feel what exactly
is the difference between abstract classes and interfaces? Because just-like abstract classes, interfaces also
provide just a prototype of the methods and the implementing classes have to define those methods. (more
about interfaces in Chapter 6)

The major difference comes in case of multiple inheritance. We know that we can not derive a class from
more than one base-class in C#. That is multiple inheritance is not possible. But, we may have a situation
where there is more than one base class and we need to derive a class from all those base classes and then
override the virtual methods present in all the base classes. In such a situation, instead of writing abstract
base classes, we should write interfaces. Because, a class can be derived from one base class and it can
implement many number of interfaces.

TUNGA MAHAVIDYALAYA, THIRTHAHALLI 35


TUNGA MAHAVIDYALAYA, THIRTHAHALLI 36
TUNGA MAHAVIDYALAYA, THIRTHAHALLI 37
TUNGA MAHAVIDYAAYA,
TUNGA MAHAVIDYALAYA, THIRTHAHALLI
THIRTHAHALLI 39 TUNGA MAHAVIDYAAYA, THIRTHAHALLI 40 38
TUNGA MAHAVIDYALAYA, THIRTHAHALLI 39

You might also like