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 as in the following:
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 then you need 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 many 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 that 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 be accessed by index. It is just like the non-generic collection ArrayList.
The following is an example of a List<T>:
//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 non-generic collection Queue.
The following is an example of a Queue<T>:
//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 non-generic collection Stack.
The following is an example of a Stack<T>:
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 non-generic collection Hashtable.
The following is an example of a Dictionary<K, V>:
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.
The following is an example of a generic method:
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 a ???.
The parameter type is a System.Int32.
string x, y;
MyGenericMethod<string>(x, y);
The result will be a ???.
The parameter type is a System.String.
You can also create a generic method with out parameters as follows:
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 a System.Int32.
MyGenericMethod<string>();
The result will be:
The type of x is a System.String.
Note: you can omit the type parameter if the generic method requires arguments, because the compiler can infer the type parameter based on the member parameters. However if your generic method doesn't take any parameters then 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 learn how to create a custom generic collection.