Вы находитесь на странице: 1из 42

P a g e | 1 | Module 4 Source : diginotes.

in
Module 4
Implementing properties in access field properties

IMPLEMENTING ENCAPSULATION BY USING METHODS


Consider this example
In this the user can give the screen position values as negative which is not correct
i.e if the fields are public we cannot provide encapsulation

struct ScreenPosition
{
public int x;
public int y;
public ScreenPosition(int x,int y)
{
this.x=checkRange(x);
this.y= checkRange(y);
}
public static int checkRange (int value)
{
if (value < 0 || value > 1024)
{
throw new ArgumentOutOfRangeException;
}
return value;
}
static void Main ()
{
ScreenPosition s = new ScreenPosition (25,40);
s.x = -100;
s.y=-200;//the screen position cant be in negative
}
}

If the fields are public, the user can misuse it. We are not enforcing encapsulation.
Ex: s.x = -100;

One solution is make the fields private and write the public methods to access it,this
solution enforces the encapsulation but it doesn’t has a natural field like syntax,instead it
uses awkward method based syntax.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 2 | Module 4 Source : diginotes.in
struct ScreenPosition
{
private int x;
private int y;
public int getx ()
{
return this.x;
}
public void setx (int value)
{
this.x = checkRange (value);
}
public int gety()
{
return this.y;
}
public void sety (int value)
{
this.x = checkRange (value);
}
private static int checkRange (int value)
{
if (value < 0 || value > 1024)
{
throw new ArgumentOutOfRangeException;
}
return value;
}
static void Main ()
{
int xval;
ScreenPosition s = new ScreenPosition ();
xval = s.Getx ();//to retrieve the value of x
s.setx (50);
s.sety (25);
}
}

We have to access the values of x and y by methods only. This is a major drawback.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 3 | Module 4 Source : diginotes.in
Properties
Syntax:
accessModifier type PropertyName
{
set
{
…..
…..
}
get
{
…..
…..
}
}

Example:
struct Screenposition
{
private int x, y;
public int X
{
set
{
this.x = checkRange (value);
}
get
{
return this.x;
}
}
public int Y
{
set
{
this.y = checkRange (value);
}
}
private static int checkRange (int value)
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 4 | Module 4 Source : diginotes.in
if (value < 0 || value > 1024)
{
throw new ArgumentOutOfRangeException;
}
return value;
}
static void Main (String [ ] args)
{
int value;
ScreenPosition st = new ScreenPosition ();
s.X = 100;
value = s.X;
s.X+= 10;
}
}

Property:
 It is a cross between a field and a method.
 It looks like a field but acts like a method.
 User will access the same like a field but the compiler will take as a method.
 A property can contain two blocks of code which starts with set and get keywords.

Using Property
s.x = 100; //set
value = s.x; //get
s.x += 10; //both set and get

Read only property


accessModifier type PropertyName
{
get
{
…..
…..
}
}

Write only property


accessModifier type propertyName
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 5 | Module 4 Source : diginotes.in
set
{
…..
…..
}
}

Property Accessibility
 We can change the accessibility of only one of the accessor when we define it (get or
set).
 It would not make much sense to define a property as public only to change the
accessibility of both accessor to private anyways.
 The modifier must not specify an accessibility that is less respective than that of the
property. (Don’t make the property as private. Instead make either get or set as
private.)
struct ScreenPosition
{
private int x;
public int X
{
private set
{
this.x = checkRangex (value);
}
public get
{
……
……
}
}
void change ()
{
x = 100;
}
}
Using property appropriately:
 Properties are powerful features but we have to use in the correct manner.
Ex:
class Account
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 6 | Module 4 Source : diginotes.in
private int bal;
public int Balance
{
set
{
this.bal = value;
}
get
{
return this.bal;
}
}
}
 In the above example, the balance of the user is not updated correctly. Suppose a
person has Rs. 1000 and he uses get property to withdraw Rs. 500, the Rs. 1000
balance is not changed to Rs. 500.
 So this is a poor programming method.
 To overcome this we use separate withdraw and deposit methods.and give only read
permission for balance property.
public int Balance { get{return this.bal; } }

Property restrictions:
 We can assign a value through a property of a structure or a class only after structure
of class variable is been initialized (object is created).
 Without object, we get error.
Ex:
ScreenPosition s;
s.x = 100; //Error
ScreenPosition s = new ScreenPosition ();
s.x = 100; //Valid
 We cannot use a property with ref or out arguments to a method.
Ex: void method (ref s.x) //Error
 Property can contain atmost one get accessor and one set accessor. It cannot contain
other methods or fields or properties.
 The get and set cannot take any parameters. The parameters being assigned is
passed to the set accessor automatically by using value variable.
 We can’t declare property using const and static, but we can have if condition in get
and set accessor.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 7 | Module 4 Source : diginotes.in
Declaring interfaces properties
 Interface can declare properties as well as methods.
 A class or a structure that implements this interface must implement the get as well
as set accessors for the properties.
 If the class implements the interface, we can declare the property implementation as
virtual which enables the derived classes to override the implementation.
 If we implement an interface in a class, that definition belongs to a class as well as
interface. If we want to give a specific implementation for interface, we need to go
for explicit interface definition.
Ex:
interface IScreenPosition
{
int x
{
get;
set;
}
int y
{
get;
set;
}
}
class Example : IScreenPosition
{
private int _x, _y;
public int x
{
get
{
return this._x;
}
set
{
this._x = value;
}
}
int IScreenPosition.X
{
get
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 8 | Module 4 Source : diginotes.in
{
return this._x;
}
set
{
if (value < 1024)
this._x = value;
}
}
Main ()
{
Example c = new Example ();
c.X= 10;
Console.WriteLine (c.X);
IScreenPosition i = e as IScreenPosition ();
if (i != null)
{
i.x = 100;
Console.WriteLine (i.X);
}
}
}

Generating automatic property


 We need to focus on two things with respect to properties
o Compatibility with application: The fields and properties explore themselves
by using different metadatas in assembly. If fields are public, it can be accessed
by any class but properties enforces encapsulation. If we want to change a
field to a property, entire application changes and we need to recompile the
application.
o Compatibility with interfaces: If we are implementing an interface, and the
interface defines an item as a property, the class must and should write a
property that matches the specification to the interface. We cannot implement
a property for public fields.
 Because programmers are busy, the compiler automatically generates the code for
property for the programmer’s convenience.
 It looks like a interface but here we specify access modifiers like public, private or
protected.
 We can have automatic get but not set.for example we should not change the file
when it is created or owner of the file.
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 9 | Module 4 Source : diginotes.in
 For this reason, we need to initialize the value.
Ex:
public DateTime day
{
get;
} = DateTime.now;
class Example
{
private DateTime day;
public Example (DateTime y0
{
Day = y;
}
}

Initializing Objects by using properties


 For various scenarios or combinations, we must initialize the fields. We will end up by
writing multiple constructors.
 We are not able to write a unique constructor which has same time and same
number of parameters.
 To overcome this drawback:
o Use optional parameters and pass the arguments in the constructor by using
named arguments.
o Better and transparent solution is using properties. Initialize the private fields
to set a default values and expose them as properties.
Ex:
class Triangle
{
private int s1 = 10, s2 = 10, s3 = 10;
public int Side1
{
get
{
return this.s1;
}
set
{
this.s1 = value;
}
}
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 10 | Module 4 Source : diginotes.in
public int Side2
{
get
{
return this.s2;
}
set
{
this.s2 = value;
}
}
public int Side3
{
get
{
return this.s3;
}
set
{
this.s3 = value;
}
}
}
static void Main (String [ ] args)
{
Triangle t1 = new Triangle { Side1 = 15 }; //this is called object initializer
Triangle t2 = new Triangle { Side3 = 15, Side 2=12 };
}

 When we invoke object initializer, C# generates the code for calling the default
constructor and then it calls the set accessor of the property.
 We can also call a parameterized constructor and then the object initializer.
 Remember that always the constructor will be called first and then the property.

Write a C# program which defines a class Polygon which has 2 properties number of
sides and side length. Using object initializer, create 3 types of polygons Square,
Triangle, Pentagon and print each polygon’s sides and its values.
class Polygon
{
String name;
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 11 | Module 4 Source : diginotes.in
private int sides = 10, length = 10;
public Polygon (String name)
{
this.name = name;
}
public int Side
{
get
{
return this.sides;
}
set
{
this.sides = value;
}
}
public int Length
{
get
{
return this.length;
}
set
{
this.length = value;
}
}
}
public class Demo
{
static void Main (String [ ] args)
{
Polygon p1 = new Polygon (“Square”) { Side = 4, Length = 20 };
Polygon p2 = new Polygon (“Triangle”) { Side = 3, Length = 10 };
Polygon p3 = new Polygon (“Pentagon”) { Side = 5, Length = 40 };
Console.WriteLine (p1.name + “ ” + p1.Side + “ ” + p1.Length);
Console.WriteLine (p2.name, p2.Side, p2.Length);
Console.WriteLine (p3.name, p3.Side, p3.Length);
}
}
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 12 | Module 4 Source : diginotes.in
Output:
Square 4 20
Triangle 3 10
Pentagon 5 40

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 13 | Module 4 Source : diginotes.in
Chapter 2
Indexer
C# provides a set of operators that we can use to access and manipulate the individual bits
like NOT operator, Left Shift, Right Shift, OR, etc.
Suppose for a binary number, we need to check if the 6th bit from right is 0 or not. We use
bits = bits & (1<<5) != 0
To set bit to 0
bits bits & ~(1<<5)
To set bit to 0
bits = bits 1 (1<<5)
Unfortunately this is not an abstract solutions because we need to repeat this logic to set or
unset for specific index.
For that purpose we can’t give square bracket notation for integer because it works only for
arrays.
We can’t give
bits [3] = true;
bits [5] = false;
We cannot use [ ] notation in int type variables.
So we need to create a new type that acts like and use like arrays of bool variables but
implemented for int. That is knows as indexer.

Indexer:
 Indexer is same like property as smart field where a property encapsulates a single
value in a class but an indexer encapsulates a set of values.
 An indexer is not a method. There is not parenthesized containing a parameter but
there are square brackets specifying the index.
 All indexer uses this keyword.
 A class or a structure can use at most 1 indexer or it can overload an indexer but
always the name of the indexer is this.
 Indexer acts like a property which has get and set accessor.
 The index specified in the indexer is populated when the indexer is called.
Ex:
struct IntBIts
{
private int bits;
public IntBits(int val)
{
bits = val;
}
public bool this[int index]
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 14 | Module 4 Source : diginotes.in
{
get
{
return (bits &(1<<index) != 0);
}
set
{
if(value)
bits = bits|(1<<index);
else
bits = bits&(1<<index);
}
}
public void display()
{
Console.WriteLine(“bits = {0}”, bits);
}
}
Class program
{
Static void Main(string [ ] args)
{
IntBits b = new IntBits(126);
bool ans = b [6] //retrieves bool at index 6;
b[0] = true;
b[3] = false;
b.display (); //ans will be 119;
}
}

UNDERSTANDING INDEXER ACCESSOR


 When we read an indexer the compiler automatically translates the array like code
into call to get accessor of that indexer.
bool p = b [5]; //get
 When we write to an indexer the compiler automatically translates the array like
code into call to set accessor of that indexer.
b [1] = true; //set
 It is also possible to use an indexer in a combined read/write context
b [5] = b[5]^true; //set and get

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 15 | Module 4 Source : diginotes.in
Write a program to show how array is implemented using indexer.
class IndexerDemo
{
private String [ ] nameList = new String [10];
public String this [this Index]
{
get
{
if (Index >= 0 && Index < 10)
return nameList [Index];
}
set
{
if (Index >= 0 && Index < 10)
nameList [Index] = value;
}
}
static void Main (String [ ] args)
{
IndexerDemo ID = new IndexerDemo ();
ID[0] = “Piddy”;
ID[5] = “Pradeep”;
for (int i = 0; i < ID.length; i++)
Console.WriteLine (ID [i]);
}
}

Comparing indexers and arrays:


 Indexers can use non numerical subscript like String, char, float, double.But arrays
can use only integers as subscript.
 Indexers can be overloaded just like methods
public int this [String Index]
{
….
….
}
public int this [String Index]
{
….
….
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 16 | Module 4 Source : diginotes.in
}
 Indexers cannot be used as ref and out as parameters because it already is a
reference type.
Method(ref bits[5]);

Comparison between property array and indexer array


Property array
 It is possible that the property can return an array but since the arrays are reference
types so exposing an array as a property creates the possibility of accidently
overwriting the data.
class PropertyDemo
{
private int [ ] data = new int [10];
public int [ ] Data
{
set
{
this.data [i] = value;
}
get
{
return this.data [i];
}
}
static void Main (String [ ] args)
{
PropertyDemo PD = new PropertyDemo ();
int [ ] value = PD.Data;//reference to reference copy
value [0] ++;// its also updates in private field data[0] too.
}
}

Indexer Array
class IndexerDemo
{
private int [ ] data = new int [10];
public int this[int i]
{
set
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 17 | Module 4 Source : diginotes.in
this.data [i] = value;
}
get
{
return this.data [i];
}
}
static void Main (String [ ] args)
{
IndxerDemo ID = new IndexerDemo ();
int [ ] value =new int[5];
value [0] =ID[0];it just assignes the value not the reference
value[0]++//upadtes only in value array not in private array data[0]
}
}

Indexers in Interface
 We can declare indexers in an interface specifying the get keyword and set keyword
or but replace the body of get and set accessor with a semicolon.
Any class or structure implements the interface must implement the indexer
accessors declared in the interface.
interface IData
{
int this [int Index]
{
get;
set;
}
}
class Example : IData
{
private int [ ] data = new int [10];
int IData. this [int index]
{
set
{
this.data [i] = value;
}
get
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 18 | Module 4 Source : diginotes.in
return this.data [i];
}
}
}

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 19 | Module 4 Source : diginotes.in
Chapter 3
Introducing generics

PROBLEM WITH OBJECT TYPE


Queue
class Queue
{
private int [ ] data;
private int head = 0, tail = 0;
private int count = 0;
private count int desize = 100;
public Queue ()
{
this.data = new int [desize];
}
public Queue (int s)
{
if (s > 0)
{
this.data = new int [s];
}
else
throw new ArgumentOutOfRangeException (“Invalid”);
}
public void Enqueue (int ele)
{
if (this.count == this.data.length)
{
throw new Exception (“Queue is full”);
}
this.data [this.head] = ele;
this.head = (this.head + 1 ) % this.data.length;
this.count ++;
}
public int dequeue ()
{
if (this.count == 0)
{
throw new Exception (“Queue empty”);
}
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 20 | Module 4 Source : diginotes.in
int ele = this.data [this.task];
this.tail = (this.tail + 1) % this.data.length;
this.count --;
return ele;
}
}
class mainDemo
{
static void Main(string [ ] args)
{
Queue q = new Queue (5);
q.Enqueue (10);
q.Dequeue (10);
Queue q = new Queue ();
}
}
 This queue works well for int data type but if we want to create queue of strings or
float or queues with refrence type we need to implement generalized queue

Generalized Queue
 Replace int with object []
Ex:
class Queue
{
private object [ ] data;
private int head = 0, tail = 0;
private int count = 0;
private count int desize = 100;
public Queue ()
{
this.data = new object [desize];
}
public Queue (int s)
{
if (s > 0)
{
this.data = new object [s];
}
else
throw new ArgumentOutOfRangeException (“Invalid”);
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 21 | Module 4 Source : diginotes.in
}
public void Enqueue (object ele)
{
if (this.count == this.data.length)
{
throw new Exception (“Queue is full”);
}
this.data [this.head] = ele;
this.head = (this.head + 1 ) % this.data.length;
this.count ++;
}
public object dequeue ()
{
if (this.count == 0)
{
throw new Exception (“Queue empty”);
}
object ele = this.data [this.task];
this.tail = (this.tail + 1) % this.data.length;
this.count --;
return ele;
}
}
class mainDemo
{
Queue q = new Queue (5);
q.Enqueue (10);
q.Dequeue (10);
Queue q = new Queue ();
}

Generalized class
 It is important to know that we have to cast the values returned by a method.
Ex:
Console.WriteLine (q.Dequeue ()); //Error
 This compiler throws an error saying that implicit type casting is not possible.
 Suppose if we perform invalid casting, say
circle mycircle = (circle) q.Dequeue ();
But the deleted element is Horse Object.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 22 | Module 4 Source : diginotes.in
So syntactically it is correct but at the runtime throws an exception i.e.
System.InvalidCastException.
 Generalized class and methods consumes additional memory and processor time if
the runtime needs to convert an object to a value type.
 For this purpose we use generic class.

Generic class
 Syntax
class classname <T >
{

} //<T> is called placeholder

Replace object [ ] with T

class Queue <T>


{
private T [ ] data;
private int head = 0, tail = 0;
private int count = 0;
private cons int dsize = 100;
public Queue ()
{
this.data = new T [dsize];
}
public Queue (int s)
{
if (s > 0)
this.data = new T (s);
else
throw new ArgumentOutOfRangeException (“Invalid”);
}
public void Enqueue (T ele)
{
……
……
count ++;
}
public T Dequeue ()
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 23 | Module 4 Source : diginotes.in
if
{
……
……
}
int ele = this.data [this.tail];
this.tail = (this.tail + 1) % this;
…..
…..
}

Difference between Generic class and Generalized class:


 Generic classes uses type parameters. Generalized class accepts any type of
parameter and at o different type.
 In generic classes, boxing type casting is not required but generalized class needs it.
 In generic class, based on type, a separate code is generated by the compiler. This is
called as constructed type.
Generics and contraints
If we want to ensure that type parameter by the generic class identifies a type
that provides certain methods.
By using a constraint we can limit the type parameter of generic class to
implement a particular set of interfaces

Defining interfaces for the generic classes


class classname <type> where Type : Interface –name <Type>

class Example <T> where T : IScreenPosition <T>

Comparing two objects:


 An interface IComparable has declared a method CompareTo().
 It returns integer values.
 If the current object < value of the parameter object, it returns -1
 If the current object =value of the parameter object, it returns 0
 If the current object > value of the parameter object, it returns 1

interface IComparable
{
int CompareTo (object i);
}

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 24 | Module 4 Source : diginotes.in
Implementation in program:
interface IComparable
{
int CompareTo (object i);
}
class Circle : IComparable
{
int r;
int Area () => Math.PI * r * r;
public int CompareTo (object x)
{
Circle c = (Circle) x;
if (this.Area () > c.Area ())
return 1;
if (this.Area () == c.Area ())
return 0;
if (this.Area () < c.Area ())
return -1;
}
}

Drawback:
 Since the method can accept any type of object, sometimes we might get an
InvalidTypeCastException.
 So we can use generic interface IComparable<T> to avoid this.

Generic Interface IComaparable<T>


Implementation using program:
interface IComparable <T>
{
int CompareTo (T x);
}
class Example<T> where T : IComparable<T>
{
int r;
int Area () => Math.PI * r * r;
public int CompareTo (T x)
{
if (this.Area () > x.Area ())
return 1;
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 25 | Module 4 Source : diginotes.in
if (this.Area () == x.Area ())
return 0;
if (this.Area () < x.Area ())
return -1;
}
}

Binary Tree Algorithm


 Every note must have atmost 2 child nodes, i.e., left child and right child.
 The left child node must be lesser than the parent node and the right side node must
be larger than the parent node.
Algorithm:
if tree B is empty
then
construct a new tree B with node I
root > I
else
if ( current node > I )
if left tree empty
create left subtree with I
else
insert I node to left subtree
else
if right subtree is empty
create right subtree with I
else
insert I node to right subtree

Ex: 1, 5, -2, 1, 6

Inorder Algorithm:
if left child is not empty
display the content of left subtree
display the root
if left child is not empty
display the content of left subtree

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 26 | Module 4 Source : diginotes.in
C# program for binary tree
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BinaryTree
{
public class Tree<TItem> where TItem : IComparable<TItem>
{
public TItem NodeData { get; set; }
public Tree<TItem> LeftTree { get; set; }
public Tree<TItem> RightTree { get; set; }
public Tree(TItem nodeValue)
{
this.NodeData = nodeValue;
this.LeftTree = null;
this.RightTree = null;
}
public void Insert(TItem newItem)
{
TItem currentNodeValue = this.NodeData;
if (currentNodeValue.CompareTo(newItem) > 0)
{
// Insert the item into the left subtree
if (this.LeftTree == null)
{
this.LeftTree = new Tree<TItem>(newItem);
}
else
{
this.LeftTree.Insert(newItem);
}
}
else
{
// Insert the new item into the right subtree
if (this.RightTree == null)
{
this.RightTree = new Tree<TItem>(newItem);
}
else
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 27 | Module 4 Source : diginotes.in
{
this.RightTree.Insert(newItem);
}
public string WalkTree()
{
string result = "";
if (this.LeftTree != null)
{
result = this.LeftTree.WalkTree();
}
result += $" {this.NodeData.ToString()} ";
if (this.RightTree != null)
{
result += this.RightTree.WalkTree();
}
return result;
}
}
}

Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BinaryTree;

namespace BinaryTreeTest
{
class Program
{
static void Main(string[] args)
{
Tree<int> tree1 = new Tree<int>(10);
tree1.Insert(5);
tree1.Insert(11);
tree1.Insert(5);
tree1.Insert(-12);
tree1.Insert(15);
tree1.Insert(0);
tree1.Insert(14);
tree1.Insert( -8);
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 28 | Module 4 Source : diginotes.in
tree1.Insert(10);
tree1.Insert(8);
tree1.Insert(8);
string sortedData = tree1.WalkTree();
Console.WriteLine($"Sorted data is: {sortedData}");
Tree<string> tree2 = new Tree<string>("Hello");
tree2.Insert("hi");
tree2.Insert("hello");
tree2.Insert("how");
tree2.Insert("are");
tree2.Insert("you");
tree2.Insert("Im");
tree2.Insert("fine");
tree2.Insert("You");
tree2.Insert("Are");
tree2.Insert("Feeling");
tree2.Insert("now");
tree2.Insert("!");
sortedData = tree2.WalkTree();
Console.WriteLine($"Sorted data is: {sortedData}");
Console.ReadLine();
}
}
}

Generic method
 With generic method we can specify the types of the parameters and return type by
using a type parameter in a manner similar to that used when we define a generic
class.
 In this way we define generalized methods that are safe and avoid overhead of
casting
 The syntax is same like the type parameter syntax as that of generic class
returntype methodname<T>(T parameters)
Example
static void swap<T>(ref T a,ref T b)
{
T temp=a;
a=b;
b=temp;
}
static void Main(string []agrs)
{
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 29 | Module 4 Source : diginotes.in
int a=5,b=6;
Swap<int>(ref a,ref b);
String s1=”hi”,s2=”hello”;
Swap<string>(ref s1,ref s2);
}

Generic method for binary tree:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BinaryTree;

namespace BuildTree
{
class Program
{
static void Main(string[] args)
{
Tree<char> charTree = null;
Tree<int> it = null ;
InsertIntoTree<char>(ref charTree, 'M', 'X', 'A', 'M', 'Z', 'Z', 'N');
string sortedData = charTree.WalkTree();
Console.WriteLine($"Sorted data is {sortedData}");
InsertIntoTree<int>(ref it, 10,2,1,4,15,3,2,1,4);
string intdata = it.WalkTree();
Console.WriteLine($"Sorted data is {intdata}");
Console.ReadLine();
}
static void InsertIntoTree<TItem>(ref Tree<TItem> tree, params TItem[]
data) where TItem : IComparable<TItem>
{
foreach(TItem datum in data)
{
if(tree==null)
{
tree = new Tree<TItem>(datum);
}
else
{
tree.Insert(datum);

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 30 | Module 4 Source : diginotes.in
}
}
}
}
}

Variance and generic interfaces:


interface IData <T>
{
void setData (T d);
T getData ();
}

class Example <T> : IData <T>


{
private T val;
void IData <T>.setData (T d)
{
this.val = d;
}
T IData <T>.getData ()
{
return this.val;
}
static void Main(String [ ] args)
{
Example<string> e = new Example<string>();
IData<string> ie = e;
ie.setData (“Hello”);
Console.WriteLine (ie.getData ());
IData <object> oe = e; //explicit type casting is required
IData <object> oe = (IData<object>) e; //runtime will throw typecast
exception
}
}
 This is known as invariant.
 We cannot assign the interface <A > object to the reference of type interface <B
>even if type A is derived from type B, because for the type safety purpose the C# will
restrict this.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 31 | Module 4 Source : diginotes.in
Covariance
 We can assign a reference of interface <A> to the reference of interface <B >as long
as there is a valid conversion from type A to type B.or type A derives from type B
 Syntax : interface interfacename <out T>
{
T get Data();
}
 This is not legal for value type it is only applicable for reference type.
Program
interface ISetting <T>
{
void setData (T d);
}
interface IRetrieve <out T>
{
T getData ();
}
class Example <T> : ISetting <T>, IRetrieve <T>
{
private T val;
void ISetting <T>.setData (T d)
{
this.val = d;
}
T IRetrieve <T>.getData ()
{
return this.val;
}
static void Main (String [ ] args)
{
Example <string> e = new Example <string> ();
ISetting <string> ie = e;
ie.setData (“Hello”);
IRetrieve <string> re = e;
Console.WriteLine (re.getData ());
IRetrieve <object> oe = e;
Console.WriteLine (oe.getData ());
}
}

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 32 | Module 4 Source : diginotes.in
Contravariance
 It is the opposite of covariant interface.
 It enable us to use generic interface to reference of object of type B through a
reference of type A, as long as type B is derives from type A.
 The ‘in’ keyword tell that the C# compiler that we can either pass the type T as the
parameter type to a method or pass any type that derives from T.

Program
interface IComparing <in T>
{
int Compare(T x,T y);
}
class Example : IComparing <object>
{
int IComparing<object>.Compare (object x,object y)
{
int xcode = x.GetHashCode();
int ycode = y.GetHashCode();
if (xcode == ycode)
return 0;
if (xcode < ycode)
return -1;
return 1;
}
static void Main(String [ ] args)
{
Example e = new Example ();
IComparing <object> ie = e;
IComparing <String> sc = e;
IComparing <A> ae = e;
}
}

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 33 | Module 4 Source : diginotes.in
CHAPTER 4
Collections
The Microsoft .NET framework provides several classes that collect elements together that
an application can access the elemnts in specialized ways.these collection classes live in
System.Collections.Generic namespace.
 We have to create instances for the generic classes to use them.
 System.Collections.Generic namespace contains all these generic classes.
 Different types of collection:
o List
o LinkedList
o Stack
o Queue
o Hash
Brief overview of these collections
collection Description
List<T> A list of objects that can be accessed by index as with an array,
but additional methods with which to search the list and sort the
contents of the list
Queue<T> A first in first out data structure with methods to add an element
to one end of the queue remove an item from another end, and
examine the item without removing it
Stack<T> A first in last out data structure with methods to push an item on
to the top of the stack pop an item from the top of the stack,
and examine the item at the top of the stack without removing it
LinkedList <T> A double ended ordered list optimized to support insertion and
removal at either end, this collection can act like queue or stack
but it also supports random access like a list does
HashSet <T> An unordered set of values that is optimized for the fast retrieval
of data, it provides set oriented methods for determining
whether the items it holds are the subset of those in another
HashSet <T> object as Well as computing the intersection and
union of HashSet <T>objects.
Dictionary<TKey,TValue> A collection of values that can be identified and retrieved by
using keys rather than indexers.
SortedList<Tkey,TValue> A sorted of key/value pairs. The keys must implement the
IComparable <T>interface

List<T>
 It is the simplest form of collection classes.
 We can use square brackets and the index for displaying the elements of the list as
like array, but adding or deleting an element is not possible by using array syntax.
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 34 | Module 4 Source : diginotes.in
 No need to specify the capacity when we create it because it will grow or shrink as
we add or delete elements.
 Methods:
o Add (val) – Inserts a value at the end of the list.
o Insert (index, val) – Inserts a value at a specific index position.
o Remove (val) – Removes the values. If there are multiple same values, it
removes the first occurrence of the value. It returns the value that is removed.
o RemoveAt (index) – Removes value from the specified index position.
o Sort – Sorts the values in ascending order.
 Uses property count
o It uses count to keep track of number of values in the list.
Ex:
static void Main()
{
List <int> l = new List <int> ();
l.add (2);
foreach (int x in new int [5] {10, 4, 15, -4, 3})
l.add (x);
l.Insert (3,100);
i l.Remove (100); //100 is removed
l.RemoveAt (3); //15 is removed (index 3)
//Displaying the list elements
Console.WriteLine (“Elements in list:”);
foreach (int x in l)
Console.WriteLine (x);
l.sort(); //Sorts the list values in ascending order
Console.WriteLine (“Elements in list after sorting:”);
foreach (int x in l)
Console.WriteLine (x);
}
Output:
Elements in list:
10
4
-4
3
Elements in list after sorting:
-4
3
4
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 35 | Module 4 Source : diginotes.in
10

LinkedList<T>
 It is an implementation of Doubly Linked List.
 It uses 5 properties:
o Previous – Holds the reference of previous node.
o Value – Hold the value.
o Next – Holds the reference of next node.
o First – Holds the reference of first record.
o Last – Holds the reference of last records

 Methods:
o AddFirst (value) – Inserts the value at beginning movind the previous first item
up and setting its previous property to refer new item.
o AddLast (value) – Inserts the value at the end by setting new node previous
property will hold the reference of previous last node.
o AddBefore (LinkedListNode<T>node, value) – Inserts value before the node.
o AddAfter (LinkedListNode<T>node, value) – Inserts value after the node.
o (both requires to traverse to retrive the node)
o RemoveFirst () – Removes the first node.
o RemoveLast () – Removes the last node.
o Remove (val) – Removes the first occurance node whose value matches with
the argument passed.
Ex:
Static void Main ()
{
LinkedList <int> l = new LinkedList <int> ();
l.AddFirst (5);
foreach (int x in new int [3] {10, 20, 30})
l.AddLast (x);
l.AddBefore (l.Find (20), 15);
l.AddAfter (l.Find (20), 25);
l.RemoveFirst ();
l.RemoceLast ();
l.Remove (25);

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 36 | Module 4 Source : diginotes.in
//Displaying
Console.WriteLine (“The list is:”);
for (LinkedListNode <int> i = l.First ; i != null ; i = i.Next)
Console.WriteLine (i.Value);
Output:
The list is:
15
20

Display can also be done using foreach loop.


foreach(int x in l)
{
Console.WriteLine (x);
}

Queue <T>
It implements first in first out mechanism an element is inserted at the back and removed
from the front.
 Methods:
o Enqueue (val) – Inserts the value to the back of the queue.
o Dequeue-removes the element from the front
 Property – Count
o Keeps a track of the number of elements in the queue.
Ex:
Main ()
{
Queue <int> q = new Queue <int> ();
q.Enqueue (10);
foreach (int x in new int [3] {20,30,40})
q.Enqueue (x);
//Display
foreach (int x in q)
{
Console.WriteLine (x);
}
Console.WriteLine(“first element deleted is {0}”,q.Deque());
}
Output:
10
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 37 | Module 4 Source : diginotes.in
20
30
40
first element deleted is 10

Stack <T>
It implements last in first out mechanism an element joins the stack at the top(push(ele))
and leaves the stack at the top(pop()).
 Methods:
o Push (ele)
o Pop ()
 Property – Count
o Keeps track of number of elements in the stack.
Ex:
Main()
{
Stack <int> s = new Stack <int> ();
s.Push (10);
foreach (int x in new int [3] {20,30,40})
s.Push (x);
//Display
foreach (int x in s)
{
Console.WriteLine (x);
}
Console.WriteLine(“popped element deleted is {0}”,s.Pop());

}
Output:
10
20
30
40
popped element deleted is 40

Dictionary <Tkey, Tvalue>


 Usually List<T> has integer index.But sometimes for mapping we require other types
like string double, etc.This type of arrays is known as associated arrays.
Syntax : Dictionary <Tkey, Tvalue>
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 38 | Module 4 Source : diginotes.in
 Dictionary maintains 2 arrays, one for keys and one for values.
 Dictionary cannot contain duplicate keys. If we try to call the ADD() method for the
key which is already present we get the Exception
 Methods:
o Add (key, value) – Adds the elements to the dictionary.
 Syntax : object.Add (key, value)
If we try to add a key which is already present, we get an exception.
 Internally the dictionary uses sparse data structure when it has plenty of memory.
 The dictionary can grow faster as we insert more elements
 To retrieve we use foreach loop.

Displaying:
foreach (KeyValuePair <String, int> x in d)
{
Console.WriteLine (“Name = {0} , Age = {1}”, x.key, x.value);
}
 Properties: It uses 2 properties
o Key – To retrieve keys.
o Value – To retrieve values.
Program
Class Program
{
static void Main(string [ ] args)
{
Dictionary<string,int>ages=new Dictionary<string,int>();
ages.Add(“john”,51);
ages.Add(“ram”,41);
ages.Add(“sam”,34);
ages.Add(“john”,21);//Exception
ages[“john”]=21//overwrites 51 to 21
Console.WriteLine (“the contents are”);
foreach (KeyValuePair <String, int> x in ages)
{
Console.WriteLine (“Name = {0} , Age = {1}”, x.key, x.value);
}
}
}

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 39 | Module 4 Source : diginotes.in
SortedList <TKey, Tvalue>
 Similar to dictionary but the difference is that keys arrays is always sorted.
 It takes longer time to insert data into a sorted list but retrieval is faster and uses less
memory.
 Even SortedList cannot contain duplicate keys
 First the key is sorted in the key array. After sorting, it obtains the index of all the
keys. Based on the index, respective values are stored in the value array of same
index to ensure that key value pairs remain synchronized.

Program
class Program
{
static void Main(string [ ] args)
{
SortedList<string,int>ages=new SortedList <string,int>();
ages.Add(“john”,51);
ages.Add(“ram”,51);
ages.Add(“john”,21);//Exception
ages[“john”]=21//overwrites 51 to 21
Console.WriteLine (“the contents are”);
foreach (KeyValuePair <String, int> x in ages)
{
Console.WriteLine (“Name = {0} , Age = {1}”, x.key, x.value);
}
}
}

HashSet<T>
Is optimized for performing set operations such as determing set membership and
generating the union and interaction of sets.
 Methods:
o Add (val) – Inserts val to the hash set.
o UnionWith (Hashset) – Finds union of 2 hash sets and stores to first hash set.
 Syntax: hs1.UnionWith (hs2)
 Hs1 <- hs1 U hs2
o IntersectWith (HashSet) – Finds the intersection of 2 hash sets and stores to
first hash set.
 Syntax: hs1.IntersectWith (hs2)
 Hs1 <- hs1 ∩ hs2

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 40 | Module 4 Source : diginotes.in
o ExceptWith (hashset) – Finds the difference between 2 hash sets and stores to
first hash set.
 Syntax: hs1 <- hs1 – hs2
We can also determine whether the HashSet<T> collection is superset or subset by using
IsSubsetOf(),IsSuperSet(),IsProperSupersetOf methods this returns Boolean values

Program:
static void Main()
{
HashSet <string> a= new List <string> (){“ram”,”sam”,”Kumar”};
HashSet <string> b= new List <string> (){“ramesh”,”sam”,”Kumar”,”ajay”};
foreach(string x in a)
{
Console.WriteLine(x);
}
foreach(string x in b)
{
Console.WriteLine(x);
}
a.UnionWith(b);
a.IntersectWith(b);
a.ExceptWith(a);
}

Collection Initializer
 If collection has add methods we can initialize it similar to array
 List<int> num=new List<int>( ){10,20,30,40,50,60};
 Internally the c# compiler converts this intailiztion to a series of calls to the Add
method.
 This is not supported for Queue<T> and Stack<T>

for Dictionary<string,int>ages=new Dictionary<string,int>()


{
[“john”]=51,
[“ram”]=21,
[“ganesh”]=41
};
 We can also specify each key/value pair as an anonymous type in the initializer.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in


P a g e | 41 | Module 4 Source : diginotes.in
Dictionary<string,int>ages=new Dictionary<string,int>()
{
{“john”,51},
{“ram”},21,
{“ganesh”,41}
};

FIND METHODS PREDICATES AND LAMBDA EXPRESSIONS


 Dictionary and SortedList has key so that searching a record is easy but LinkedList<T>
and List<T> has non-keyed access we need to find method to search a record.
 Find(node) returns Boolean value indicating whether the item matches.
 FindLast(node)which returns the last matching object.
 FindAll() which returns a List<T> collection of all matching objects.
 The easy way to specify the predicate is to use a lambda expression.
 Lambda expression that returns a method.
Struct Person
{
public int ID(get;set;}
public string Name{get;set;}
}
List<Person> l=new List<Person>( )
{
New Person( ){ID=1,Name=”john”,age=23},
New Person( ){ID=2,Name=”ram”,age=22},
New Person( ){ID=3,Name=”satish”,age=23},
New Person( ){ID=4,Name=”hitesh”,age=24},
};
Person match=l.Find((person p)=>{return p.ID==3;});
Console.WriteLine(“id={0},name={1},match.ID,match,Name);
List<person> match=l.FindAll(p=>p.ID==3);
List<person> match=l.FindLast(p=>p.ID==3);

Comparing arrays and collections


 An array instance has a fixed size and cannot grow or shrink.a collection can
dynamically resize itself as required.
 An array can have more than one dimension.a collection is linear.however the items
in collection can be collections themselves,so we can imitate a multidimensional
array as a collection of collections.
 We store and retrieve an item in an array by using an index,not all the collections
support this notion
Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in
P a g e | 42 | Module 4 Source : diginotes.in
 Many of the collection classes provide a ToArray method that creates abd populated
an array containing the items in the collection.the items are copied to the array and
are not removed from the collection.

Pushpanathan G, Dept. of CSE, CITech, Bangalore Source : diginotes.in

Вам также может понравиться