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

Module 4_Easy_understanding

Module 4 covers defining extensible types in C#, focusing on encapsulation, properties, indexers, and generics. It explains how to implement encapsulation using accessors and mutators, create read-only and write-only properties, and utilize indexers for array-like access to class members. Additionally, it introduces generics, their advantages, constraints, and the differences between generic and non-generic collections.

Uploaded by

bindiyap
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

Module 4_Easy_understanding

Module 4 covers defining extensible types in C#, focusing on encapsulation, properties, indexers, and generics. It explains how to implement encapsulation using accessors and mutators, create read-only and write-only properties, and utilize indexers for array-like access to class members. Additionally, it introduces generics, their advantages, constraints, and the differences between generic and non-generic collections.

Uploaded by

bindiyap
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 32

Module 4: Defining extensible types in C#

Implementing properties to access fields:


Encapsulation:
Encapsulation is the procedure of covering up of data and functions into a single unit. An encapsulated
object is often called an abstract data type.

We need of Encapsulation for the following reasons:


One of the fundamental principles of object-oriented programming.
A process of hiding all the internal details of an object from the outside world.
Provides a way to protect data from accidental corruption.
Gives the ability to validate the values before the object user change or obtain the value.
Makes implementation inaccessible to other parts of the program and protect from whatever actions
might be taken outside the function or class.

Encapsulation using accessors and mutators:


Rather than defining the data in the form of public, we can declare those fields as private so that we
achieved encapsulation. The Private data are manipulated using accessor (get: store the data to private
members) and mutator (set: to interact with the variable) methods.
Syntax:
set { <accessor-body> }
get { <accessor-body> }

Example:
using System; class GetSetDemo1 { static void
namespace Chapter4_Examples{ class Main(){
Student{ Student st1 = new Student();
string name, branch, usn; st1.Studusn ="1RX12MCA01";
Console.WriteLine("USN: "+st1.Studusn);
public string Studusn{
Console.ReadKey();
set{ usn = value; } }
get{return usn;} }
} }

}
In the above example, we see the usage of Encapsulation by using properties. The property is
composed using a get block(accessor) and set block (Mutator). The get block returns the value of
some property field. The set block sets the value of some property field with the contents of “value”
token.

Encapsulation using Properties:


Write-Only Property: Properties can be made write-only. This is accomplished by having only a set
mutator in the property implementation.

Example:
class Student{
string name, branch, usn;
public string Studusn{
set{usn = value;}
}
}
In this example, the property “Studusn” is having only set (mutator) but not get (accessor). So Studusn
can called as a “write-only property”.

Creating Read-Only Fields: Properties can be made read-only. This is accomplished by having only get
accessor in property implementation.
Example 2.4: In the below example, the property “Studusn” is having only get (accessor) but not set
(mutator). So can call Studusn as a “read-only property”.
Accessor methods, also known as getter methods, are methods that allow you to retrieve the value of
an object.
Mutator methods, also known as setter methods, are methods that allow you to modify the value of
an object.

Example:
using System;
class ReadOnly{ static void Main()
namespace Class_Demos{
{
class Student{ string studusn;
Student st1 = new Student();
public Student(){
Console.WriteLine("USN: "
studusn="1RX12MCA01";
+ st1.Studusn);
}
Console.ReadKey();
public string Studusn{ get{
}
return studusn;
}
}
}
}
}

“static” property: C# also supports “static” properties. The static members are accessed at the class
level, not from an instance (object) of that class. Static properties are manipulated in the same manner
as static methods, as seen here:
Example: Assume that the Student type defines a point of static data to represent the name of the
institution studying these students. You may define a static property as follows:
using System; class StaticProperty{ static void
namespace Class_Demos{ Main(){
class Student{ Student.Institution = "RNSIT";
string name, branch, usn; Console.WriteLine("InstitutionName:"
static string instName; +Student.Institution);
public static string Institution Console.ReadKey();
{ }
set { instName = value; } }
get { return instName; } }
}
}

Indexers:
Indexers allow you to use a class as an array and enable an object to access the members of a class
using an index notation.

Syntax:
<access-modifier> <Return_Type> this [argument_list] {
Where,
get { // return the value specified by index }
set { // set the value specified by index }
}
The access modifier can be private, public, protected or internal
Return type can be any valid C# data type, such as int, float, double, string….
this keyword shows that the object is of the current class.
argument list specifies the parameters of the indexer.
Must have at least one parameter; otherwise the compiler gives and error.
Allows you to have multiple parameters and each parameter can be a different type, separated
by commas.
Parameter types can be int, enum, or string.
All indexers in the same class should have different signatures.
The get and set portions accessors is the same as that of the indexer to which they belong.

Example:

using System;
namespace Class_Demos{
class Student {
string[] usn = new string[3];
public string this[int index]
{ set { usn[index] = value; }
get {
if (index < 0 || index >= usn.Length) return null;
else
return (usn[index]);
}
}}
class IndexerDemo {
public static void Main(){
Student slist = new Student();
slist[0] = "1RN12MCA01";
slist[1] = "1RN12MCA02";
slist[2] = "1RN12MCA03";
for (int i = 0; i < 3; i++)
Console.WriteLine(slist[i]);
Console.ReadKey();
}
}}

Indexers have the following additional features:


Inheritance – Allows inheritance, which means a derived class can inherit a base class indexer.
However, modifiers such as virtual and override are used at the property level, not at the accessor
level.
Polymorphism – Allows polymorphism, which means the derived class can override a base class
indexer.
Uniqueness – Provides a signature that uniquely identifies an indexer.
Non – Static – Indexer cannot be static. If you declare, the compiler generates an error.

Indexer Overloading:
An indexer is used to treat an object as an array. It is used to provide index to an object to obtain
values from the object.
Implementing an indexer requires you to use brackets ([ ]) with an object to get and set a value of the
object.
Indexer are declared as properties, with the difference that in case of indexers, you do not need to
provide name to them. You need to use the “this” keyword to define an indexer.

Example:
using System;
namespace Class_Demos{
class MyClass{
string[] mydata;
int arrsize;
public MyClass(int size){
arrsize = size;
mydata = new string[size];
for (int i = 0; i < size; i++)
mydata[i] = "DataValue";
}
public string this[int position]{
set{ mydata[position] = value; }
get{return (mydata[position]); }
}
public string this[string data]{
set{
for (int i=0; i<arrsize; i++){
if (mydata[i] == data)
mydata[i] = value;
}
}
get{
int count = 0;
for (int i = 0; i < arrsize; i++){
if (mydata[i] == data)
count = count + 1;
}
return count.ToString();
}
}
}
class IndOverload{
static void Main(){
int size = 10;
MyClass obj=new MyClass(size);
obj[1] = "Hello";
obj[3] = "Good Morning";
obj[7] = "Welcome";
obj["DataValue"] = "Have a nice day";
for (int i = 0; i < size; i++)
Console.WriteLine("obj[{0}]: {1}", i, obj[i]);

Console.WriteLine("\n\nNumber of \"Have a nice day\"entries:{0}",obj["Have a nice day"]);


Console.Read();
}
}
}

Introduction Generics:
C# Generics
Generic means the general form, not specific. In C#, generic means not specific to a particular data
type.

C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods,
properties, events, delegates, and operators using the type parameter and without the specific data
type. A type parameter is a placeholder for a particular type specified when creating an instance of the
generic type.

A generic type is declared by specifying a type parameter in an angle bracket after a type name, e.g.
TypeName<T> where T is a type parameter.

Generic Class
Generic classes are defined using a type parameter in an anglebrackets after the class name. The
following defines a generic class.

Example: Define Generic Class


class DataStore<T>
{
public T Data { get; set; }
}

Generic Class Characteristics


A generic class increases the reusability. The more type parameters mean more reusable it becomes.
However, too much generalization makes code difficult to understand and maintain.
A generic class can be a base class to other generic or non-generic classes or abstract classes.
A generic class can be derived from other generic or non-generic interfaces, classes, or abstract
classes.
Generic Fields
A generic class can include generic fields. However, it cannot be initialized.

Example: Generic Field


class DataStore<T>
{
public T data;
}
The following declares a generic array.

Example: Generic Array


class DataStore<T>
{
public T[] data = new T[10];
}
Generic Methods
A method declared with the type parameters for its return type or parameters is called a generic
method.

Example: Generic Methods


class DataStore<T>
{
private T[] _data = new T[10];

public void AddOrUpdate(int index, T item)


{
if(index >= 0 && index < 10)
_data[index] = item;
}

public T GetData(int index)


{
if(index >= 0 && index < 10)
return _data[index];
else
return default(T);
}
}

Advantages of Generics
Generics increase the reusability of the code. You don't need to write code to handle different data
types.
Generics are type-safe. You get compile-time errors if you try to use a different data type than the one
specified in the definition.
Generic has a performance advantage because it removes the possibilities of boxing and unboxing.

C# Generic Constraints
C# allows you to use constraints to restrict client code to specify certain types while instantiating
generic types. It will give a compile-time error if you try to instantiate a generic type using a type that
is not allowed by the specified constraints.

You can specify one or more constraints on the generic type using the where clause after the generic
type name.

Syntax:
GenericTypeName<T> where T : contraint1, constraint2
The following example demonstrates a generic class with a constraint to reference types when
instantiating the generic class.
Example: Declare Generic Constraints
class DataStore<T> where T : class
{
public T Data { get; set; }
}
Above, we applied the class constraint, which means only a reference type can be passed as an
argument while creating the DataStore class object. So, you can pass reference types such as class,
interface, delegate, or array type. Passing value types will give a compile-time error, so we cannot pass
primitive data types or struct types.

DataStore<string> store = new DataStore<string>(); // valid


DataStore<MyClass> store = new DataStore<MyClass>(); // valid
DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // valid
DataStore<IEnumerable> store = new DataStore<IMyInterface>(); // valid
DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid
//DataStore<int> store = new DataStore<int>(); // compile-time error

where T : struct
The following example demonstrates the struct constraint that restricts type argument to be non-
nullable value type only.

Example: struct Constraints


class DataStore<T> where T : struct
{
public T Data { get; set; }
}

DataStore<int> store = new DataStore<int>(); // valid


DataStore<char> store = new DataStore<char>(); // valid
DataStore<MyStruct> store = new DataStore<MyStruct>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // compile-time error
//DataStore<ArrayList> store = new DataStore<ArrayList>(); // compile-time error
where T : new()
The following example demonstrates the struct constraint that restricts type argument to be non-
nullable value type only.

Example: new() Constraint


class DataStore<T> where T : class, new()
{
public T Data { get; set; }
}

DataStore<MyClass> store = new DataStore<MyClass>(); // valid


DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time error
//DataStore<int> store = new DataStore<int>(); // compile-time error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // compile-time error

where T : baseclass
The following example demonstrates the base class constraint that restricts type argument to be a
derived class of the specified class, abstract class, or an interface.

Example: BaseClass Constraint


class DataStore<T> where T : IEnumerable
{
public T Data { get; set; }
}

DataStore<ArrayList> store = new DataStore<ArrayList>(); // valid


DataStore<List> store = new DataStore<List>(); // valid
//DataStore<string> store = new DataStore<string>(); // compile-time error
//DataStore<int> store = new DataStore<int>(); // compile-time error
//DataStore<IMyInterface> store = new DataStore<IMyInterface>(); // compile-time error
//DataStore<MyClass> store = new DataStore<MyClass>(); // compile-time error

C# Generic & Non-generic Collections


C# includes specialized classes that store series of values or objects are called collections.

There are two types of collections available in C#: non-generic collections and generic collections.

The System.Collections namespace contains the non-generic collection types and


System.Collections.Generic namespace includes generic collection types.

In most cases, it is recommended to use the generic collections because they perform faster than non-
generic collections and also minimize exceptions by giving compile-time errors.
C# - ArrayList
In C#, the ArrayList is a non-generic collection of objects whose size increases dynamically. It is the
same as Array except that its size increases dynamically.

An ArrayList can be used to add unknown data where you don't know the types and the size of the
data.

Create an ArrayList
The ArrayList class included in the System.Collections namespace. Create an object of the ArrayList
using the new keyword.
Example: Create an ArrayList
using System.Collections;

ArrayList arlist = new ArrayList();


// or
var arlist = new ArrayList(); // recommended

Adding Elements in ArrayList


Use the Add() method or object initializer syntax to add elements in an ArrayList.

An ArrayList can contain multiple null and duplicate values.

Example: Adding Elements in ArrayList


// adding elements using ArrayList.Add() method
var arlist1 = new ArrayList();
arlist1.Add(1);
arlist1.Add("Bill");
arlist1.Add(" ");
arlist1.Add(true);
arlist1.Add(4.5);
arlist1.Add(null);

// adding elements using object initializer syntax


var arlist2 = new ArrayList()
{
2, "Steve", " ", true, 4.5, null
};

Accessing an ArrayList
The ArrayList class implements the IList interface. So, elements can be accessed using indexer, in the
same way as an array. Index starts from zero and increases by one for each subsequent element.

An explicit casting to the appropriate types is required, or use the var variable.

Example: Accessing Elements of ArrayList


var arlist = new ArrayList()
{
1,//0
"Bill",//1
300,//2
4.5f//3
};

//Access individual item using indexer


int firstElement = (int) arlist[0]; //returns 1
string secondElement = (string) arlist[1]; //returns "Bill"
//int secondElement = (int) arlist[1]; //Error: cannot cover string to int

//using var keyword without explicit casting


var firstElement = arlist[0]; //returns 1
var secondElement = arlist[1]; //returns "Bill"
//var fifthElement = arlist[5]; //Error: Index out of range

//update elements
arlist[0] = "Steve";
arlist[1] = 100;
//arlist[5] = 500; //Error: Index out of range

Iterate an ArrayList
The ArrayList implements the ICollection interface that supports iteration of the collection types. So,
use the foreach and the for loop to iterate an ArrayList. The Count property of an ArrayList returns the
total number of elements in an ArrayList.

Example: Iterate ArrayList


ArrayList arlist = new ArrayList()
{
1,
"Bill",
300,
4.5F
};

foreach (var item in arlist)


Console.Write(item + ", "); //output: 1, Bill, 300, 4.5,

for(int i = 0 ; i < arlist.Count; i++)


Console.Write(arlist[i] + ", "); //output: 1, Bill, 300, 4.5,

Insert Elements in ArrayList


Use the Insert() method to insert an element at the specified index into an ArrayList.

Signature: void Insert(int index, Object value)

Example: Insert Element in ArrayList


ArrayList arlist = new ArrayList()
{
1,//0 seond list//1
"Bill",//2
300,/3
4.5f/4
};

arlist.Insert(1, "Second Item");

foreach (var val in arlist)


Console.WriteLine(val); //1 snd list bill 300 4.5

Remove Elements from ArrayList


Use the Remove(), RemoveAt(), or RemoveRange methods to remove elements from an ArrayList.

Example: Remove Elements from ArrayList


ArrayList arList = new ArrayList() {1, null, "Bill", 300, " ", 4.5f, 300,};
arList.Remove(null); //Removes first occurance of null
arList.RemoveAt(4); //Removes element at index 4
arList.RemoveRange(0, 2);//Removes two elements starting from 1st item (0 index)

Check Element in ArrayList


Use the Contains() method to determine whether the specified element exists in the ArrayList or not. It
returns true if exists otherwise returns false.

Example: Check for Elements


ArrayList arList = new ArrayList()
{
1,
"Bill",
300,
4.5f,
300
};

Console.WriteLine(arList.Contains(300)); // true
Console.WriteLine(arList.Contains("Bill")); // true
Console.WriteLine(arList.Contains(10)); // false
Console.WriteLine(arList.Contains("Steve")); // false

ArrayList Class
The following diagram illustrates the ArrayList class.
C# - List<T>
The List<T> is a collection of strongly typed objects that can be accessed by index and having methods
for sorting, searching, and modifying list. It is the generic version of the ArrayList that comes under
System.Collections.Generic namespace.

List<T> Characteristics
List<T> equivalent of the ArrayList, which implements IList<T>.
It comes under System.Collections.Generic namespace.
List<T> can contain elements of the specified type. It provides compile-time type checking and doesn't
perform boxing-unboxing because it is generic.
Elements can be added using the Add(), AddRange() methods or collection-initializer syntax.
Elements can be accessed by passing an index e.g. myList[0]. Indexes start from zero.
List<T> performs faster and less error-prone than the ArrayList.
Creating a List
The List<T> is a generic collection, so you need to specify a type parameter for the type of data it can
store. The following example shows how to create list and add elements.

Example: Adding elements in List


List<int> primeNumbers = new List<int>();
primeNumbers.Add(2); // adding elements using add() method
primeNumbers.Add(3);
primeNumbers.Add(5);
primeNumbers.Add(7);

var cities = new List<string>();


cities.Add("New York");
cities.Add("London");
cities.Add("Mumbai");
cities.Add("Chicago");
cities.Add(null);// nulls are allowed for reference type list

//adding elements using collection-initializer syntax


var bigCities = new List<string>()
{
"New York",
"London",
"Mumbai",
"Chicago"
};

In the above example, List<int> primeNumbers = new List<int>(); creates a list of int type. In the same
way, cities and bigCities are string type list. You can then add elements in a list using the Add() method
or the collection-initializer syntax.

You can also add elements of the custom classes using the collection-initializer syntax. The following
adds objects of the Student class in the List<Student>.

Example: Add Custom Class Objects in List


var students = new List<Student>() {
new Student(){ Id = 1, Name="Bill"},
new Student(){ Id = 2, Name="Steve"},
new Student(){ Id = 3, Name="Ram"},
new Student(){ Id = 4, Name="Abdul"}
};

Adding an Array in a List


Use the AddRange() method to add all the elements from an array or another collection to List.

AddRange() signature: void AddRange(IEnumerable<T> collection)

Example: Add Arrays in List


string[] cities = new string[3]{ "Mumbai", "London", "New York" };

var popularCities = new List<string>();

// adding an array in a List


popularCities.AddRange(cities);

var favouriteCities = new List<string>();

// adding a List
favouriteCities.AddRange(popularCities);

Accessing a List
A list can be accessed by an index, a for/foreach loop, and using LINQ queries. Indexes of a list start
from zero. Pass an index in the square brackets to access individual list items, same as array. Use a
foreach or for loop to iterate a List<T> collection.

Example: Accessing List


List<int> numbers = new List<int>() { 1, 2, 5, 7, 8, 10 };
Console.WriteLine(numbers[0]); // prints 1
Console.WriteLine(numbers[1]); // prints 2
Console.WriteLine(numbers[2]); // prints 5
Console.WriteLine(numbers[3]); // prints 7

// using foreach LINQ method


numbers.ForEach(num => Console.WriteLine(num + ", "));//prints 1, 2, 5, 7, 8, 10,

// using for loop


for(int i = 0; i < numbers.Count; i++)
Console.WriteLine(numbers[i]);
Accessing a List using LINQ
The List<T> implements the IEnumerable interface. So, we can query a list using LINQ query syntax or
method syntax, as shown below.

Example: LINQ Query on List


var students = new List<Student>() {
new Student(){ Id = 1, Name="Bill"},
new Student(){ Id = 2, Name="Steve"},
new Student(){ Id = 3, Name="Ram"},
new Student(){ Id = 4, Name="Abdul"}
};

//get all students whose name is Bill


var result = from s in students
where s.Name == "Bill"
select s;

foreach(var student in result)


Console.WriteLine(student.Id + ", " + student.Name);
Insert Elements in List
Use the Insert() method inserts an element into the List<T> collection at the specified index.

Insert() signature:void Insert(int index, T item);

Example: Insert elements into List


var numbers = new List<int>(){ 10, 20, 30, 40 };

numbers.Insert(1, 11);// inserts 11 at 1st index: after 10.

foreach (var num in numbers)


Console.Write(num);

Remove Elements from List


Use the Remove() method to remove the first occurrence of the specified element in the List<T>
collection. Use the RemoveAt() method to remove an element from the specified index. If no element
at the specified index, then the ArgumentOutOfRangeException will be thrown.

Remove() signature: bool Remove(T item)

RemoveAt() signature: void RemoveAt(int index)

Example: Remove elements from List


var numbers = new List<int>(){ 10, 20, 30, 40, 10 };

numbers.Remove(10); // removes the first 10 from a list

numbers.RemoveAt(2); //removes the 3rd element (index starts from 0)

//numbers.RemoveAt(10); //throws ArgumentOutOfRangeException

foreach (var el in intList)


Console.Write(el); //prints 20 30
Check Elements in List
Use the Contains() method to determine whether an element is in the List<T> or not.

Example: Contains()
var numbers = new List<int>(){ 10, 20, 30, 40 };
numbers.Contains(10); // returns true
numbers.Contains(11); // returns false
numbers.Contains(20); // returns true
List<T> Class Hierarchy
The following diagram illustrates the List<T> hierarchy.
C# - SortedList<TKey, TValue>
The SortedList<TKey, TValue>, and SortedList are collection classes that can store key-value pairs that
are sorted by the keys based on the associated IComparer implementation. For example, if the keys are
of primitive types, then sorted in ascending order of keys.

C# supports generic and non-generic SortedList. It is recommended to use generic SortedList<TKey,


TValue> because it performs faster and less error-prone than the non-generic SortedList.

SortedList Characteristics
SortedList<TKey, TValue> is an array of key-value pairs sorted by keys.
Sorts elements as soon as they are added. Sorts primitive type keys in ascending order and object keys
based on IComparer<T>.
Comes under System.Collection.Generic namespace.
A key must be unique and cannot be null.
A value can be null or duplicate.
A value can be accessed by passing associated key in the indexer mySortedList[key]
Contains elements of type KeyValuePair<TKey, TValue>
It uses less memory than SortedDictionary<TKey,TValue>.
It is faster in the retrieval of data once sorted, whereas SortedDictionary<TKey, TValue> is faster in
insertion and removing key-value pairs.

Creating a SortedList
The following example demonstrates how to create a generic SortedList<TKey, TValue>, and add key-
value pairs in it.

Example: Create a SortedList and Add Elements


//SortedList of int keys, string values
SortedList<int, string> numberNames = new SortedList<int, string>();
numberNames.Add(3, "Three");
numberNames.Add(1, "One");
numberNames.Add(2, "Two");
numberNames.Add(4, null);
numberNames.Add(10, "Ten");
numberNames.Add(5, "Five");

//The following will throw exceptions


//numberNames.Add("Three", 3); //Compile-time error: key must be int type
//numberNames.Add(1, "One"); //Run-time exception: duplicate key
//numberNames.Add(null, "Five");//Run-time exception: key cannot be null

Accessing SortedList
Specify a key in the indexer sortedList[key], to get or set a value in the SortedList.

Example: Access SortedList Values


SortedList<int,string> numberNames = new SortedList<int,string>()
{
{3, "Three"},
{1, "One"},
{2, "Two"}
};

Console.WriteLine(numberNames[1]); //output: One


Console.WriteLine(numberNames[2]); //output: Two
Console.WriteLine(numberNames[3]); //output: Three
//Console.WriteLine(numberNames[10]); //run-time KeyNotFoundException

numberNames[2] = "TWO"; //updates value


numberNames[4] = "Four"; //adds a new key-value if a key does not exists

Remove Elements from SortedList


Use the Remove(key) and RemoveAt(index) methods to remove key-value pairs from a SortedList.

Example: Remove Elements


SortedList<int,string> numberNames = new SortedList<int,string>()
{
{3, "Three"},
{1, "One"},
{2, "Two"},
{5, "Five"},
{4, "Four"}
};

numberNames.Remove(1);//removes key 1 pair


numberNames.Remove(10);//removes key 1 pair, no error if not exists

numberNames.RemoveAt(0);//removes key-value pair from index 0


//numberNames.RemoveAt(10);//run-time exception: ArgumentOutOfRangeException

foreach(var kvp in numberNames)


Console.WriteLine("key: {0}, value: {1}", kvp.Key , kvp.Value );

SortedList Class Hierarchy


The following diagram illustrates the SortedList hierarchy.

C# - Dictionary<TKey, TValue>
The Dictionary<TKey, TValue> is a generic collection that stores key-value pairs in no particular order.

Dictionary Characteristics
Dictionary<TKey, TValue> stores key-value pairs.
Comes under System.Collections.Generic namespace.
Implements IDictionary<TKey, TValue> interface.
Keys must be unique and cannot be null.
Values can be null or duplicate.
Values can be accessed by passing associated key in the indexer e.g. myDictionary[key]
Elements are stored as KeyValuePair<TKey, TValue> objects.
Creating a Dictionary
You can create the Dictionary<TKey, TValue> object by passing the type of keys and values it can store.
The following example shows how to create a dictionary and add key-value pairs.

Example: Create Dictionary and Add Elements


IDictionary<int, string> numberNames = new Dictionary<int, string>();
numberNames.Add(1,"One"); //adding a key/value using the Add() method
numberNames.Add(2,"Two");
numberNames.Add(3,"Three");

//The following throws run-time exception: key already added.


//numberNames.Add(3, "Three");

foreach(KeyValuePair<int, string> kvp in numberNames)


Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);

//creating a dictionary using collection-initializer syntax


var cities = new Dictionary<string, string>(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

foreach(var kvp in cities)


Console.WriteLine("Key: {0}, Value: {1}", kvp.Key, kvp.Value);

Access Dictionary Elements


The Dictionary can be accessed using indexer. Specify a key to get the associated value. You can also
use the ElementAt() method to get a KeyValuePair from the specified index.

Example: Access Dictionary Elements


var cities = new Dictionary<string, string>(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

Console.WriteLine(cities["UK"]); //prints value of UK key


Console.WriteLine(cities["USA"]);//prints value of USA key
//Console.WriteLine(cities["France"]); // run-time exception: Key does not exist

//use ContainsKey() to check for an unknown key


if(cities.ContainsKey("France")){
Console.WriteLine(cities["France"]);
}
//use TryGetValue() to get a value of unknown key
string result;

if(cities.TryGetValue("France", out result))


{
Console.WriteLine(result);
}

//use ElementAt() to retrieve key-value pair using index


for (int i = 0; i < cities.Count; i++)
{
Console.WriteLine("Key: {0}, Value: {1}",
cities.ElementAt(i).Key,
cities.ElementAt(i).Value);
}

Update Dictionary
Update the value of a key by specifying a key in the indexer. It will throw the KeyNotFoundException if
a key does not exist in the dictionary, therefore use the ContainsKey() method before accessing
unknown keys.

Example: Update Dictionary Elements


var cities = new Dictionary<string, string>(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities["UK"] = "Liverpool, Bristol"; // update value of UK key


cities["USA"] = "Los Angeles, Boston"; // update value of USA key
//cities["France"] = "Paris"; //throws run-time exception: KeyNotFoundException

if(cities.ContainsKey("France")){
cities["France"] = "Paris";
}

Remove Elements in Dictionary


The Remove() method deletes an existing key-value pair from a dictionary. The Clear() method deletes
all the elements of the dictionary.

Example: Remove Dictionary Elements


var cities = new Dictionary<string, string>(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities.Remove("UK"); // removes UK
//cities.Remove("France"); //throws run-time exception: KeyNotFoundException
if(cities.ContainsKey("France")){ // check key before removing it
cities.Remove("France");
}

cities.Clear(); //removes all elements

Dictionary Class Hierarchy


The following diagram illustrates the generic Dictionary class hierarchy.

C# - Hashtable
The Hashtable is a non-generic collection that stores key-value pairs, similar to generic
Dictionary<TKey, TValue> collection. It optimizes lookups by computing the hash code of each key and
stores it in a different bucket internally and then matches the hash code of the specified key at the
time of accessing values.

Hashtable Characteristics
Hashtable stores key-value pairs.
Comes under System.Collections namespace.
Implements IDictionary interface.
Keys must be unique and cannot be null.
Values can be null or duplicate.
Values can be accessed by passing associated key in the indexer e.g. myHashtable[key]
Elements are stored as DictionaryEntry objects.
Creating a Hashtable
The following example demonstrates creating a Hashtable and adding elements.
Example: Create and Add Elements
Hashtable numberNames = new Hashtable();
numberNames.Add(1,"One"); //adding a key/value using the Add() method
numberNames.Add(2,"Two");
numberNames.Add(3,"Three");

//The following throws run-time exception: key already added.


//numberNames.Add(3, "Three");

foreach(DictionaryEntry de in numberNames)
Console.WriteLine("Key: {0}, Value: {1}", de.Key, de.Value);

//creating a Hashtable using collection-initializer syntax


var cities = new Hashtable(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

foreach(DictionaryEntry de in cities)
Console.WriteLine("Key: {0}, Value: {1}", de.Key, de.Value);

Update Hashtable
You can retrieve the value of an existing key from the Hashtable by passing a key in indexer. The
Hashtable is a non-generic collection, so you must type cast values while retrieving it.

Example: Update Hashtable


//creating a Hashtable using collection-initializer syntax
var cities = new Hashtable(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

string citiesOfUK = (string) cities["UK"]; //cast to string


string citiesOfUSA = (string) cities["USA"]; //cast to string

Console.WriteLine(citiesOfUK);
Console.WriteLine(citiesOfUSA);

cities["UK"] = "Liverpool, Bristol"; // update value of UK key


cities["USA"] = "Los Angeles, Boston"; // update value of USA key

if(!cities.ContainsKey("France")){
cities["France"] = "Paris";
}

Remove Elements in Hashtable


The Remove() method removes the key-value that match with the specified in the Hashtable. It throws
the KeyNotfoundException if the specified key not found in the Hashtable, so check for an existing key
using the ContainsKey() method before removing.
Use the Clear() method to remove all the elements in one shot.

Example: Remove Elements from Hashtable


var cities = new Hashtable(){
{"UK", "London, Manchester, Birmingham"},
{"USA", "Chicago, New York, Washington"},
{"India", "Mumbai, New Delhi, Pune"}
};

cities.Remove("UK"); // removes UK
//cities.Remove("France"); //throws run-time exception: KeyNotFoundException

if(cities.ContainsKey("France")){ // check key before removing it


cities.Remove("France");
}

cities.Clear(); //removes all elements

Hashtable Class Hierarchy


The following diagram illustrates the Hashtable class hierarchy.
C# - Stack<T>
Stack is a special type of collection that stores elements in LIFO style (Last In First Out). C# includes the
generic Stack<T> and non-generic Stack collection classes. It is recommended to use the generic
Stack<T> collection.

Stack is useful to store temporary data in LIFO style, and you might want to delete an element after
retrieving its value.

Stack<T> Characteristics
Stack<T> is Last In First Out collection.
It comes under System.Collection.Generic namespace.
Stack<T> can contain elements of the specified type. It provides compile-time type checking and
doesn't perform boxing-unboxing because it is generic.
Elements can be added using the Push() method. Cannot use collection-initializer syntax.
Elements can be retrieved using the Pop() and the Peek() methods. It does not support an indexer.
Creating a Stack
You can create an object of the Stack<T> by specifying a type parameter for the type of elements it can
store. The following example creates and adds elements in the Stack<T> using the Push() method.
Stack allows null (for reference types) and duplicate values.

Example: Create and Add Elements in Stack


Stack<int> myStack = new Stack<int>();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

foreach (var item in myStack)


Console.Write(item + ","); //prints 4,3,2,1,

Pop()
The Pop() method returns the last element and removes it from a stack. If a stack is empty, then it will
throw the InvalidOperationException. So, always check for the number of elements in a stack before
calling the Pop() method.
Example: Access Stack using Pop()
Stack<int> myStack = new Stack<int>();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

Console.Write("Number of elements in Stack: {0}", myStack.Count);

while (myStack.Count > 0)


Console.Write(myStack.Pop() + ",");

Console.Write("Number of elements in Stack: {0}", myStack.Count);

Peek()
The Peek() method returns the lastly added value from the stack but does not remove it. Calling the
Peek() method on an empty stack will throw the InvalidOperationException. So, always check for
elements in the stack before retrieving elements using the Peek() method.

Example: Retrieve Elements usign Peek()


Stack<int> myStack = new Stack<int>();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

Console.Write("Number of elements in Stack: {0}", myStack.Count);// prints 4

if(myStack.Count > 0){


Console.WriteLine(myStack.Peek()); // prints 4
Console.WriteLine(myStack.Peek()); // prints 4
}

Console.Write("Number of elements in Stack: {0}", myStack.Count);// prints 4

Contains()
The Contains() method checks whether the specified element exists in a Stack collection or not. It
returns true if it exists, otherwise false.

Example: Contains()
Stack<int> myStack = new Stack<int>();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);

myStack.Contains(2); // returns true


myStack.Contains(10); // returns false

C# - Queue<T>
Queue is a special type of collection that stores the elements in FIFO style (First In First Out), exactly
opposite of the Stack<T> collection. It contains the elements in the order they were added. C# includes
generic Queue<T> and non-generic Queue collection. It is recommended to use the generic Queue<T>
collection.

Queue<T> Characteristics
Queue<T> is FIFO (First In First Out) collection.
It comes under System.Collection.Generic namespace.
Queue<T> can contain elements of the specified type. It provides compile-time type checking and
doesn't perform boxing-unboxing because it is generic.
Elements can be added using the Enqueue() method. Cannot use collection-initializer syntax.
Elements can be retrieved using the Dequeue() and the Peek() methods. It does not support an
indexer.

The following figure illustrates the Queue collection:

Creating a Queue
You can create an object of the Queue<T> by specifying a type parameter for the type of elements it
can store. The following example creates and adds elements in the Queue<T> using the Enqueue()
method. A Queue collection allows null (for reference types) and duplicate values.

Example: Create and Add Elements in the Queue


Queue<int> callerIds = new Queue<int>();
callerIds.Enqueue(1);
callerIds.Enqueue(2);
callerIds.Enqueue(3);
callerIds.Enqueue(4);

foreach(var id in callerIds)
Console.Write(id); //prints 1234
Retrieve Elements from a Queue
The Dequeue() and the Peek() method is used to retrieve the first element in a queue collection. The
Dequeue() removes and returns the first element from a queue because the queue stores elements in
FIFO order. Calling the Dequeue() method on an empty queue will throw the InvalidOperation
exception. So, always check that the total count of a queue is greater than zero before calling it.

Example: Reading Queue


Queue<string> strQ = new Queue<string>();
strQ.Enqueue("H");
strQ.Enqueue("e");
strQ.Enqueue("l");
strQ.Enqueue("l");
strQ.Enqueue("o");

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 5

while (strQ.Count > 0)


Console.WriteLine(strQ.Dequeue()); //prints Hello

Console.WriteLine("Total elements: {0}", strQ.Count); //prints 0

Contains()
The Contains() method checks whether an item exists in a queue or not. It returns true if the specified
item exists, otherwise returns false.

Contains() Signature: bool Contains(object obj);

Example: Contains()
Queue<int> callerIds = new Queue<int>();
callerIds.Enqueue(1);
callerIds.Enqueue(2);
callerIds.Enqueue(3);
callerIds.Enqueue(4);
callerIds.Contains(2); //true
callerIds.Contains(10); //false

You might also like