Sunday, May 30, 2010

object oriented programming in c#

Object-Oriented Programming


5.1 Write your own class

In CSharp we can write our own class. Object-oriented programming is essentially

programming in terms of smaller units called objects. An object oriented program is

composed of one or more objects. Each object holds some data (fields or attributes)

as defined by its class. The class also defines a set of functions (also called methods

or operations) which can be invoked on its objects. Generally the data is hidden

within the objects (instances) and can be accessed only through functions defined

by its class (encapsulation). One or more objects (instances) can be created from

a class by a process called instantiation. The process of deciding which attributes

and operations will be supported by an object (i.e. defining the class) is called

abstraction. We say the state of the object is defined by the attributes it supports

and its behaviour is defined by the operations it implements. The term passing a

message to an object means invoking its operation. Sometimes the set of operations

supported by an object is also referred to as the interface exposed by this object.

C# also introduces properties. Properties act like methods to the creator of the

class but look like fields to the client of the class.

Polymorphism refers to the ability of objects to use different types without regard

to the details.

Constructors are methods that are invoked when objects are instantiated. The CLR

defines one, but it is better practice to code the constructors that are required. All

objects are created using new.

A Default Constructor Generated by compiler if none exists. They have the same

name as the class, no return type, no arguments are required, all fields are initialized

to zero, have public accessibility. Note that writing any constructor stops default

creation.

A Private Constructor prevents unwanted objects from being created. Instance

63

64 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

methods cannot be called. Static methods can be called. Commonly used to implement

procedural functions.

A Static Constructor is called by class loader at run time. It is used to initialize

static members and is guaranteed to be called before instance constructor. It cannot

have parameters. Use this to declare an access modifier.

A default constructor may look like the following example.

public Person1() { }

The following program shows an example for class Person. The Person is described

by his name, age and sex. Thus we have three attributes:

myName, myAge, mySex.

These private data members are only visible inside the body of class Person1.

// Person1.cs

using System;

class Person1

{

private string myName = "N/A";

private int myAge = 0;

private char mySex = ’n’;

// default constructor

public Person1() { }

// constructor

public Person1(string name,int age,char sex)

{

this.myName = name;

this.myAge = age;

this.mySex = sex;

}

// declare a Name property of type string

public string Name

{

get { return myName; }

set { myName = value; }

}

5.1. WRITE YOUR OWN CLASS 65

public int Age

{

get { return myAge; }

set { myAge = value; }

}

public char Sex

{

get { return mySex; }

set { mySex = value; }

}

public override string ToString()

{

return "Name = " + Name + ", Age = " + Age + ", Sex = " + Sex;

}

public override bool Equals(object o)

{

if((myName==((Person1) o).myName) &&

(myAge==((Person1) o).myAge) &&

(mySex==((Person1) o).mySex))

return true;

else return false;

}

public static void Main()

{

// create a new Person object using default constructor

Person1 person1 = new Person1();

// Set some values on the person object

person1.Name = "Joe";

person1.Age = 99;

person1.Sex = ’m’;

Console.WriteLine("Person details - {0}",person1);

Person1 person2 = new Person1();

person2.Name = "Jane";

person2.Age = 31;

person2.Sex = ’f’;

Console.WriteLine("Person details - {0}",person2);

Person1 person3 = new Person1();

person3.Name = "Jane";

66 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

person3.Age = 31;

person3.Sex = ’f’;

Console.WriteLine("Person details - {0}",person3);

bool same = person2.Equals(person3);

Console.WriteLine("same person = " + same);

Person1 person4 = new Person1("otto",42,’m’);

Console.WriteLine("Person details: " + person4.myName);

Console.WriteLine("Person details: " + person4.mySex);

// array of persons

Person1[] pmany = new Person1[2];

pmany[0] = new Person1("Carl",23,’m’);

pmany[1] = new Person1("Ola",7,’f’);

Console.WriteLine("name of person[0]: " + pmany[0].myName);

Console.WriteLine("sex of person[1]: " + pmany[1].mySex);

} // end Main

}

class Person1 defines three private member variables, myName, myAge, mySex.

These variable are visible only inside the body of class Person1. To access these

variable outside the class we use the special property methods Name, Age, and Sex.

The CSharp compiler translates for example the Name property to a pair of methods,

namely

public string get_Name()

{ return myName; }

public void set_Name(string value)

{ myName = value; }

The class Person1 contains the Main() method. In some application it would be

better to keep the class Person1 without the Main() method and have an extra file

which calls the Person objects. The file Person.cs only contains the class Person

and no Main() method.

// Person.cs

using System;

class Person

{

public string myName = "N/A";

public int myAge = 0;

public char mySex = ’n’;

5.1. WRITE YOUR OWN CLASS 67

// default constructor

public Person() { }

// constructor

public Person(string name,int age,char sex)

{

this.myName = name;

this.myAge = age;

this.mySex = sex;

}

// declare a Name property of type string

public string Name

{

get { return myName; }

set { myName = value; }

}

public int Age

{

get { return myAge; }

set { myAge = value; }

}

public char Sex

{

get { return mySex; }

set { mySex = value; }

}

public override string ToString()

{

return "Name = " + Name + ", Age = " + Age + ", Sex = " + Sex;

}

public override bool Equals(object o)

{

if((myName==((Person) o).myName) &&

(myAge==((Person) o).myAge) &&

(mySex==((Person) o).mySex))

return true;

else return false;

}

}

68 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

To generate the Person.dll file we run

csc /t:library Person.cs

The file PersonMain.cs contains the Main() method.

// PersonMain.cs

using System;

class PersonMain

{

public static void Main()

{

// create a new Person object using default constructor

Person person1 = new Person();

// Set some values on the person object

person1.Name = "Joe";

person1.Age = 99;

person1.Sex = ’m’;

Console.WriteLine("Person details - {0}",person1);

Person person2 = new Person();

person2.Name = "Jane";

person2.Age = 31;

person2.Sex = ’f’;

Console.WriteLine("Person details - {0}",person2);

Person person3 = new Person();

person3.Name = "Jane";

person3.Age = 31;

person3.Sex = ’f’;

Console.WriteLine("Person details - {0}",person3);

bool same = person2.Equals(person3);

Console.WriteLine("same person = " + same);

// increment the age of person3

person3.Age++;

Console.WriteLine("person3 new age: " + person3.Age);

Person person4 = new Person("otto",42,’m’);

Console.WriteLine("Person details: " + person4.myName);

Console.WriteLine("Person details: " + person4.mySex);

5.2. OVERRIDE METHODS 69

// array of persons

Person[] pmany = new Person[2];

pmany[0] = new Person("Carl",23,’m’);

pmany[1] = new Person("Ola",7,’f’);

Console.WriteLine("name of person[0]: " + pmany[0].myName);

Console.WriteLine("sex of person[1]: " + pmany[1].mySex);

} // end Main

}

To get the PersonMain.exe file we run

csc /r:Person.dll PersonMain.cs

However, we can also use the short-cut

csc Person.cs PersonMain.cs

to generate the PersonMain.exe file.

5.2 Override Methods

When we write our own class in most cases we should override the methods

string ToString(), bool Equals(), object Clone()

An example is given below

// Point3D.cs

using System;

public class Point3D

{

public double X;

public double Y;

public double Z;

public Point3D() { } // default constructor

public Point3D(double x,double y,double z)

{

this.X = x;

this.Y = y;

this.Z = z;

}

70 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

// square of distance between two Points

public double distance(Point3D p1,Point3D p2)

{

return (p1.X-p2.X)*(p1.X-p2.X)+(p1.Y-p2.Y)*(p1.Y-p2.Y)+(p1.Z-p2.Z)*(p1.Z-p2.Z);

}

public override string ToString()

{

return String.Format("({0},{1},{2})",X,Y,Z);

}

public override bool Equals(object o)

{

if((X==((Point3D) o).X) && (Y==((Point3D) o).Y) && (Z==((Point3D) o).Z))

return true;

else return false;

}

public object Clone()

{

object o = new Point3D(X,Y,Z);

return o;

}

}

An application of this class is

// Point3DMain.cs

using System;

public class Point3DMain

{

public static void Main()

{

double x = 2.1;

double y = 3.1;

double z = 4.5;

Point3D p1 = new Point3D(x,y,z);

Console.WriteLine("p1 = " + p1);

double a = 2.1;

double b = 3.1;

double c = 4.5;

Point3D p2 = new Point3D(a,b,c);

5.3. INHERITANCE 71

bool r = p1.Equals(p2);

Console.WriteLine("r = " + r);

double k = 2.0;

double m = 1.0;

double n = 7.5;

Point3D p3 = new Point3D(k,m,n);

Point3D p4 = new Point3D(0.0,0.0,0.0);

p4 = (Point3D) p3.Clone(); // type conversion

Console.WriteLine("p4 = " + p4);

Point3D q = new Point3D();

double d = q.distance(p1,p3);

Console.WriteLine("d = " + d);

}

}

5.3 Inheritance

Inheritance is one of the primary concepts of object-oriented programming. It

allows us to reuse existing code. In the next program we use inheritence. The

class Car is derived from class Vehicle. In the class Car we use code from the

class Vehicle. First we must declare our intention to use Vehicle as the base

class of Car. This is accomplished through the Car class declaration

public class Car : Vehicle

Then the colon, : , and the keyword base call the base class constructor. C# supports

single class inheritance only.

A sealed class protects against inheritence.

An abstract class can only be used as a base class of other classes. They cannot be

instantiated and may contain abstract methods and accessors. It is not possible to

modify an abstract class with the sealed modifier, thus the class cannot be inherited.

// MVehicle.cs

using System;

class Vehicle

{

private int weight;

private int topSpeed;

72 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

private double price;

public Vehicle() {}

public Vehicle(int aWeight,int aTopSpeed,double aPrice)

{

weight = aWeight;

topSpeed = aTopSpeed;

price = aPrice;

}

public int getWeight() { return weight;}

public int getTopSpeed() { return topSpeed; }

public double getPrice() { return price; }

public virtual void print()

{

Console.WriteLine("Weight: {0} kg",weight);

Console.WriteLine("Top Speed: {0} km/h",topSpeed);

Console.WriteLine("Price: {0} Dollar",price);

}

} // end class Vehicle

class Car : Vehicle

{

private int numberCylinders;

private int horsepower;

private int displacement;

public Car() { }

public Car(int aWeight,int aTopSpeed,double aPrice,int aNumberCylinders,

int aHorsepower,int aDisplacement) : base(aWeight,aTopSpeed,aPrice)

{

numberCylinders = aNumberCylinders;

horsepower = aHorsepower;

displacement = aDisplacement;

}

public int getNumberCylinders() { return numberCylinders; }

public int getHorsepower() { return horsepower; }

public int getDisplacement() { return displacement; }

5.3. INHERITANCE 73

public override void print()

{

base.print();

Console.WriteLine("Cylinders: {0} ",numberCylinders);

Console.WriteLine("Horsepower: {0} ",horsepower);

Console.WriteLine("Diplacement: {0} cubic cm",displacement);

}

}

class myCar

{

public static void Main()

{

Vehicle aVehicle = new Vehicle(15000,120,30000.00);

Console.Write("A vehicle: ");

aVehicle.print();

Console.WriteLine("");

Car aCar = new Car(3500,100,12000.00,6,120,300);

Console.Write("A car: ");

aCar.print();

Console.WriteLine("");

}

}

An interface looks like a class, but has no implementation. The only thing it contains

are definitions of events, indexers, methods, and/or properties. The reason interfaces

only provide definitions is because they are inherited by classes and structs, which

must provide an implementation for each interface member defined. Since interfaces

must be defined by inheriting classes and structs, they must define a contract. The

following program shows an example.

// Policies.cs

public interface Policy

{

double Rate(double principal,int period);

}

public class BronzePolicy : Policy

{

public double Rate(double p,int n)

{ return 7; }

}

public class SilverPolicy : Policy

74 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

{

public double Rate(double p,int n)

{ return (p < 25000.0) ? 8 : 10; }

}

public class GoldPolicy

{

public double Rate(double p,int n)

{ return (n < 5) ? 9 : 11; }

}

public class PlatinumPolicy : Policy

{

public double Rate(double p,int n)

{

double r = (p < 50000.0) ? 10 : 12;

if(n >= 3) r += 1;

return r;

}

}

Each policy provides a Rate method which returns the rate of interest for a given

principal and for a given period. All policy classes implement the Policy interface

except GoldPolicy which defines Rate without implementing policy. We compile

Policies.cs to create Policies.dll via

csc /t:library Policies.cs

Using reflection we can also create an instance of a class and invoke its member

methods at runtime. This feature can be used to write more generic (dynamically

extensible) programs which receive names of classes at runtime.

The investment.cs program including Main accepts principal, period and policy

name as arguments args[0], args[1], and args[2]. We compile investment.cs

as

csc /r:Policies.dll investment.cs

We would execute the program, for example,

investment 60000 5 SilverPolicy,Policies

// investment.cs

using System;

using System.Reflection;

5.4. OVERLOADING METHODS 75

class Investment

{

public static void Main(string[] args)

{

double p = Double.Parse(args[0]); // string to double

int n = Int32.Parse(args[1]); // string to int

Type t = Type.GetType(args[2]);

Policy pol = (Policy) Activator.CreateInstance(t);

double r = pol.Rate(p,n);

double amount = p*Math.Pow(1.0+r/100.0,n);

Console.WriteLine("you will get {0:#.00}",amount);

}

}

5.4 Overloading Methods

Methods in a class can be overloaded. The methods of a class may have the same

name

if they have different numbers of parameters, or

if they have different parameter types, or

if they have different parameter kinds.

We overload the method max() to find the maximum of numbers.

// methods.cs

using System;

public class Maximizer

{

public class Maximum

{

public static double max(double p,double q)

{

if(p > q) return p;

return q;

}

public static double max(double p,double q,double r)

{

return max(max(p,q),r);

}

public static double max(double[] list)

76 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

{

if(list.Length == 0) return 0;

double max = list[0];

foreach(double val in list)

{

if(val > max) max = val;

}

return max;

}

public static void Main(string[] args)

{

Console.WriteLine("maximum of 4.5 and 4.7 is {0}",max(4.5,4.7));

Console.WriteLine("maximum of 3.1, 2.4, 4.9 is {0}",max(3.1,2.4,4.9));

double[] array = new double[4];

array[0] = 3.1; array[1] = 5.7; array[2] = 3.9; array[3] = 2.1;

Console.WriteLine("maximum element in array = {0}",max(array));

} // end main

}

}

Exercise. Add a method max(int,int,int,int) to the program that find the

maximum of four integer numbers.

5.5 Operator Overloading

Operators can be overloaded (operator overloading) such that

+, -, *, \, %, []

In the next program we overload + to add two complex numbers.

// Complex.cs

using System;

public class Complex

{

public double real; // real part of complex number

public double imag; // imaginary part of number

public Complex(double real,double imag)

{

this.real = real;

this.imag = imag;

5.6. STRUCTURES AND ENUMERATIONS 77

}

public static Complex operator + (Complex c1,Complex c2)

{

c1.real = c1.real + c2.real;

c1.imag = c1.imag + c2.imag;

return c1;

}

}

class ComplexMain

{

public static void Main()

{

Complex r1 = new Complex(1.0,2.0);

Complex r2 = new Complex(2.0,1.0);

r1 = r1 + r2;

Console.WriteLine("Real: {0} Imaginary: {1}i",r1.real,r1.imag);

}

}

Exercise. Overload in the program also * for the multiplication of two complex

numbers. The multiplication of two complex numbers z1 = a + ib and z2 = c + id

(with a, b, c, d real) is given by z1 ¤ z2 = a ¤ c − b ¤ d + i(ad + bc).

5.6 Structures and Enumerations

In CSharp we can also use structures. Structures, or structs, contain properties,

methods, fields, operators, nested types, indexers and structors. Structs do not support

inheritence or destructors. The objects are stored on the stack compared to

classes which are stored on the heap. Structs are useful for small data structures

such as complex numbers, key-value pairs in a dictionary or points in a coordinate

system. They should only be used for types that are small and simple.

Enumerations are an alternative to constants when grouping related constants together.

For example, when considering temperature we can have the following.

enum Temp

{

AbsoluteZero = 0,

CosmicBackground = 2.75,

WaterFreexingPoint = 273,

WaterBoilingPoint = 373,

}

78 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

The base type for enums is integer. The following example demonstrates how to use

different types.

enum NumberChocolatesInBox :uint

{

SmallBox = 20,

MediumBox = 30,

LargeBox = 50,

}

The program shows how structs and enumeration can be used.

// enumeration.cs

using System;

enum MemberType { Lions, Elefant, Jackals, Eagles, Dogs };

struct ClubMember

{

public string Name;

public int Age;

public MemberType Group;

}

class enumeration

{

public static void Main(string[] args)

{

ClubMember a; // Value types are automatically initialized

a.Name = "John";

a.Age = 13;

a.Group = MemberType.Eagles;

ClubMember b = a; // new copy of a is assigned to b

b.Age = 17; // a.Age remains 13

Console.WriteLine("Member {0} is {1} year old and belongs to group of {2}",

a.Name,a.Age,a.Group);

} // end main

}

5.7 Delegates

A delegate in C# allows us to pass methods of one class to objects of other classes

that can call those methods. We can pass method m in class A, wrapped in a dele5.7.

DELEGATES 79

gate, to class B and class B will be able to call method m in class A. We can pass

both static and instance methods. This concept is familiar to C++ where one uses

function pointers to pass functions as parameters to other methods in the same

class or in another class. C# delegates are implemented in the .NET framework as

a class derived from System.Delegate. Thus the use of delegates involves four steps.

1. Declare a delegate object with a signature that exactly matches the method

signature that we are trying to encapsulate.

2. Define all the methods whose signature match the signature of the delegate object

that we have defined in step 1.

3. Create delegate object and plug in the methods that we want to encapsulate.

4. Call the encapsulated methods through the delegate object.

The following C# program shows the above four steps.

// Delegate.cs

using System;

// Step 1. Declare a delegate with the signature of the

// encapsulated method

public delegate void MyDelegate(string input);

// Step 2. Define methods that match with the signature

// of delegate declaration

class Class1

{

public void delegateMethod1(string input)

{

Console.WriteLine("delegateMethod1: the input to the method is {0}",input);

}

public void delegateMethod2(string input)

{

Console.WriteLine("delegateMethod2: the input to the method is {0}",input);

}

} // end class Class1

// Step 3. Create delegate object and plug in the methods

class Class2

{

public MyDelegate createDelegate()

{

Class1 c2 = new Class1();

80 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

MyDelegate d1 = new MyDelegate(c2.delegateMethod1);

MyDelegate d2 = new MyDelegate(c2.delegateMethod2);

MyDelegate d3 = d1 + d2;

return d3;

}

} // end class Class2

// Step 4. Call the encapsulated method through the delegate

class Class3

{

public void callDelegate(MyDelegate d,string input)

{

d(input);

}

} // end class Class3

class Driver

{

public static void Main()

{

Class2 c2 = new Class2();

MyDelegate d = c2.createDelegate();

Class3 c3 = new Class3();

c3.callDelegate(d,"calling the delegate");

} // end Main

}

The output is:

delegateMethod1: the input to the method is calling the delegate

delegateMethod2: the input to the method is calling the delegate

Another example is given below. Here we use delegates to compare strings.

// MyDelegate.cs

using System;

// this is the delegate declaration

public delegate int Comparer(object obj1,object obj2);

public class Name

{

public string FirstName = null;

public string LastName = null;

5.7. DELEGATES 81

public Name(string first,string last)

{

FirstName = first;

LastName = last;

}

public static int CompareFirstNames(object name1,object name2)

{

string n1 = ((Name) name1).FirstName; // type conversion

string n2 = ((Name) name2).FirstName; // type conversion

if(string.Compare(n1,n2) > 0) { return 1; }

else if(string.Compare(n1,n2) < 0) { return -1; }

else { return 0; }

} // end method CompareNames()

public override string ToString()

{ return FirstName + " " + LastName; }

} // end class Name

class SimpleDelegate

{

Name[] names = new Name[4];

public SimpleDelegate()

{

names[0] = new Name("John","Smithlone");

names[1] = new Name("Carl","Xenon");

names[2] = new Name("Rolf","Cooper");

names[3] = new Name("Ola","Jones");

}

static void Main()

{

SimpleDelegate sd = new SimpleDelegate();

// the delegate instantiation

Comparer cmp = new Comparer(Name.CompareFirstNames);

Console.WriteLine("\nBefore Sort:\n");

sd.PrintNames();

// observe the delegate argument

sd.Sort(cmp);

82 CHAPTER 5. OBJECT-ORIENTED PROGRAMMING

Console.WriteLine("\nAfter Sort:\n");

sd. PrintNames();

}

public void Sort(Comparer compare)

{

object temp;

for(int i=0;i

{

for(int j=i;j

{

// using delegate "compare" just like a normal method

if(compare(names[i],names[j])>0)

{

temp = names[i];

names[i] = names[j];

names[j] = (Name) temp;

} // end if

}

}

} // end method Sort

public void PrintNames()

{

Console.WriteLine("Names:\n");

foreach(Name name in names)

{

Console.WriteLine(name.ToString());

}

} // end method PrintNames()

}

No comments:

Post a Comment