Now consider that you ArrayList contained thousands of integers that are manipulated by your program, this for sure will affect on you application performance.
Custom Collections:
Assume that you have to create a custom collection that can only contain objects of Employee type.
public class Employee
{
string FirstName;
string LastName;
int Age;
public Employee(){}
public Employee(string fName, string lName, int Age)
{
this.Age = Age;
this.FirstName = fName;
this.Lastname = lName;
}
public override string ToString()
{
return String.Format("{0} {1} is {2} years old", FirstName, LastName, Age);
}
}
Now we will build the custom collection
public class EmployeesCollection : IEnumerable
{
ArrayList alEmployees = new ArrayList();
public EmployeesCollection() { }
//Insert Employee type
public void AddEmployee(Employee e)
{
//boxing
alEmployees.Add(e);
}
//get the employee type
public Employee GetEmployee(int index)
{
//unboxing
return (Employee)alEmployees[index];
}
//to use foreach
IEnumerator IEnumerable.GetEnumerator()
{
return alEmployees.GetEnumerator();
}
}
The problem here is that If you have many types in you application, you have to create multiple custom collections one for each type.And as you can see we also have the problem of boxing and unboxing here.
All problems you saw previously can be solved using generics, so let's see what we can do.
The System.Collections.generic namespace:
You can find a lot of generic collections in the System.Collections.Generic just like:
-
List<T>
-
Dictionary<K, V>
-
Queue<T>
-
Stack<T>
Generic collections allow you to delay the specification of the contained type until the time of creation.
By using the generic collection you avoid performance problems of the boxing and unboxing operations and don't need to create a custom collection for each type in you application.
With the generic collections it's up to you to define the type which will be contained in the collection by replacing the placeholder T by the type you want at the time of creation.
List<T>
The List<T> is a generic collection that represents a strongly typed list of objects that can accessed by index. It is just like the nongeneric collection ArrayList.
Example:
//Can only contain int type
List<int> intList = new List<int>();
//no boxing
intList.Add(10);
//no unboxing
int x = intList[0];
//Can only contain Employee objects
List<Employee> empList = new List<Employee>();
//no boxing
empList.Add(new Employee("Amr", "Ashush", 23));
//no unboxing
Employee e = empList[0];
Queue<T>
Queue<T> is a generic collection that represents a first-in, first-out (FIFO) collection of objects. It is just like the nongeneric collection Queue.
Example:
//A generic Queue collection
Queue<int> intQueue = new Queue<int>();
//Add an int to the end of the queue
//(no boxing)
intQueue.Enqueue(5);
//Returns the int at the beginning of the queue
//without removing it.
//(no unboxing)
int x = intQueue.Peek();
//Removes and returns the int at the beginning of the queue
//(no unboxing)
int y = intQueue.Dequeue();
Stack<T>
Stack<T> is a generic collection that represents a last-in-first-out (LIFO) collection of instances of the same arbitrary type. It is just like the nongeneric collection Stack.
Example:
Stack<int> intStack = new Stack<int>();
//Insert an int at the top of the stack
//(no boxing)
intStack.Push(5);
//Returns the int at the top of the stack
//without removing it.
//(no unboxing)
int x = intStack.Peek();
//Removes and returns the int at the top of the stack
//(no unboxing)
int y = intStack.Pop();
Dictionary<K, V>
Dictionary<K, V> is a generic collection that contains data in Key/Value pairs, it is just like the nongeneric collection Hashtable.
Example:
Dictionary<string, string> dictionary = new Dictionary<string, string>();
//Add the specified key and value to the dictionary
dictionary.Add("Key", "Value");
//Removes the value with the specified key from the dictionary
dictionary.Remove("Key");
//get the number of the Key/Value pairs contained in the dictionary
int count = dictionary.Count;
Generic Methods
You can create generic methods that can operate on any possible data type.
To define a generic method you specify the type parameter after the method name and before the parameters list.
Example:
public void MyGenericMethod<T>(T x, T y)
{
Console.Writeline("Parameters type is {0}", typeof(T));
}
You can define the type you want at the time you invoke the method.
int x, y;
MyGenericMethod<int>(x, y);
The result will be
Parameter type is System.Int32
string x, y;
MyGenericMethod<string>(x, y);
The result will be
Parameter type is System.String
You can also create a generic method with out parameters as follow:
public void MyGenericMethod<T>()
{
T x;
Console.WriteLine("The type of x is {0}", typeof(T));
}
Here we see the method in use:
MyGenericMethod<int>();
The result will be:
The type of x is System.Int32
MyGenericMethod<string>();
The result will be:
The type of x is System.String
Note: you can omit the type parameter if the generic method requires arguments, because the compiler can infer the type parameter base on the member parameters. However if you generic method doesn't take any parameters you are required to supply the type parameter or you will have a compile error
Example:
//a generic method that take two parameters
public void MyGenericMethod<T>(T x, T y)
{
......
}
......
string x, y;
//the compiler here will infer the type parameter
MyGenericMethod(x, y)
In the case of a generic method that doesn't take parameters
//a generic method that doesn't take parameters
public void MyGenericMethod<T>()
{
......
}
//you must supply the type parameter
MyGenericMethod<string>();
//you will have a compiler error here
MyGenericMethod();
In Part II you will see how to create generic classes, structures, delegates, interfaces and you will know how to create a custom generic collection.
Part I - Part II