Generics
Generics has been introduced in .NET 2.0. Generics allows you to define type-safe data structure without committing to actual data type. This results in significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type specific code. It is similar to C++ templates but drastically different in implementation and capabilities.
General Problem Statement :-
Let’s consider a general purpose data structure such as stack with Push() Pop() method.
public class Stack
{
readonly int m_Size;
int m_StackPointer = 0;
object[] m_Items;
public Stack():this(100)
{}
public Stack(int size)
{
m_Size = size;
m_Items = new object[m_Size];
}
public void Push(object item)
{
if(m_StackPointer >= m_Size)
throw new StackOverflowException();
m_Items[m_StackPointer] = item;
m_StackPointer++;
}
public object Pop()
{
m_StackPointer--;
if(m_StackPointer >= 0)
{
return m_Items[m_StackPointer];
}
else
{
m_StackPointer = 0;
throw new InvalidOperationException("Cannot pop an empty stack");
}
}
}
There are two problems with this object based solutions. First issue is performance. When using value types, you have to box them inorder to push and unbox them inorder to pop. Even when using reference type instead of value types, there is still a performance penalty because you have to cast from an object to actual type you interact with and incur the casting object.
Stack stack = new Stack();
stack.Push("1");
string number = (string)stack.Pop();
The second issue is type-safety. Because the complier let you cast anything from object, you lose compile time type-safety. For example the following code runs fine at compile time but run time thorws invalid cast exception.
Stack stack = new Stack();
stack.Push(1);
//This compiles, but is not type safe, and will throw an exception:
string number = (string)stack.Pop();
You can overcome this issue by creating type-specific stack for int and string.
public class IntStack
{
int[] m_Items;
public void Push(int item){...}
public int Pop(){...}
}
IntStack stack = new IntStack();
stack.Push(1);
int number = stack.Pop();
public class StringStack
{
string[] m_Items;
public void Push(string item){...}
public string Pop(){...}
}
StringStack stack = new StringStack();
stack.Push("1");
string number = stack.Pop();
Here come the Generics
Generic allows you to create type-safe classes without compromising type safety, performance and productivity.
Here is a how you define and use a generic stack.
public class Stack<T>
{
readonly int m_Size;
int m_StackPointer = 0;
T[] m_Items;
public Stack():this(100)
{}
public Stack(int size)
{
m_Size = size;
m_Items = new T[m_Size];
}
public void Push(T item)
{
if(m_StackPointer >= m_Size)
throw new StackOverflowException();
m_Items[m_StackPointer] = item;
m_StackPointer++;
}
public T Pop()
{
m_StackPointer--;
if(m_StackPointer >= 0)
{
return m_Items[m_StackPointer];
}
else
{
m_StackPointer = 0;
throw new InvalidOperationException("Cannot pop an empty stack");
}
}
}









