Generic Types
 
Generics are the most powerful feature of C# 2.0. It allows defining type-safe data structures, without committing to actual data types. In C# 1.0 we can either declare reference type or value type. But in most of the application we come across situation where we need type that can hold both reference & value type. In such situation we use generic types.
 
Why Generics?
- 
Generic type doesn't care what the type is. We can specify the type at runtime. 
- 
It avoids boxing difficulties. In C# 1.0, if we want to put any object into a List, Stack, or Queue objects, we have to take type as System.Object. 
- 
It boosts the performance of the application because we can reuse data processing algorithm without duplicating type-specific code.  
How Generic implemented:
(1)    Generic type is instantiated at run-time not compiled time
(2)    Generic type are checked at time of declaration not at instantiation
(3)    It works for both reference type & value type.
 
Let's create simple class "GenericList" using C# 1.0 & 2.0 respectively & compare them. 
 
 
Code GenericList Class (C# 1.0)
 
using System;
using System.Collections.Generic;
using System.Text; 
public class GenericList
    {
        private  object[] elements;
        private int count; 
        public GenericList()
        {
            elements = new object[10];
        }
        public object this[int index]
        {
            get { return elements[index]; }
            set { elements[index] = value; }
        } 
        public void Add (object parm)
        {
            if (count == elements.Length)
            {
                  // Increase the 
                  object[] tmpArray = null ;
                  elements.CopyTo(tmpArray,0);
                  elements = new object[count * 2];
                  elements = tmpArray;                              
            }
            elements[count] = parm;
            count = count + 1; 
        }
   }    
 
Main Method:
 
static void Main(string[] args)
        {
            Console.WriteLine("using C# 1.0"); 
            GenericList list = new GenericList();
            list.Add(20);        //Argument is boxed
            list.Add(40);        //Argument is boxed
            list.Add("Sixty");   //Error in retrieving
            Console.WriteLine("Item Added"); 
            int val = (int)list[0]; //Casting required
            Console.WriteLine("Value retrived : " + val); 
        }
 
Memory Consumption
 
In C# 1.0 boxing is necessary evil to make type system work. While working with structures of System.Collection namespace (Stacks,List,Hashtable etc) we face the problem in insertion & retrieval of values. We need to take System.object as type & System.object is reference type, so whenever we access the hashtable, the runtime has to box the values to put into the collection & need to unbox to take it out.
 
list.Add(20);        //Argument is boxed
 
In C# int takes 4 byte but when it boxed it take (4+8) 12 bytes, which is 3 times to normal size.
In C# 2.0 the type is decided at runtime so boxing does not take place.
 
Type Safe
 
When we use the statement
 
list.Add ("Sixty"); or List [3] = "sixty";
 
It compiles successfully but later on if some one pulls value and cast it into integer it fails. The problem is fixed in C# 2.0; we will get compilation error there.
 
 
Code GenericList Class (C# 2.0)
 
public class GenericList<T>
    {
        public GenericList()
        {
            elements = new T[10]; 
        } 
        private T[] elements;
        private int count;         
        public T this[int index]
        {
            get {return elements [index];}
            set {elements [index] = value;}
        }     
        public void Add (T parm)
        {
            if (count == elements.Length)
            {
                T[] tmpArray = null;
                elements.CopyTo(tmpArray, 0);
                elements = new T [count * 2];
                elements = tmpArray; 
            } 
            elements [count] = parm;
            count = count + 1;  
        } 
    }
 
Main Method:
 
static void Main(string[] args)
{
Console.WriteLine("using C# 1.0"); 
GenericList<int> genericList = new GenericList<int>();
genericList.Add (10);          //No boxing
genericList.Add (20);          //No boxing
// genericList.Add("Fifty");   //Compile Time Error
Console.WriteLine("Item Added"); 
int valGeneric = (int)genericList[0]; //No Casting Required
Console.WriteLine("Value retrived : " + valGeneric); 
}
 
Some other Points:
 
(1) Type parameter can be applied to Class, struct, interface & delegates.
 struct Buket<K, V>;
 interface ICompare<T>
(2)    Type parameter can have constraints.
 
| Constraint | Description | 
| Public class Books where T: struct | The type argument for class Books must be a value type | 
| Public class Books where T: class | The type argument for class Books must be a reference type | 
| Public class Books where T: new( ) | The type argument for class Books must have a public default constructor | 
| Public class Programmer where T: <Employee> | The type argument for class Programmer must be of Employee type. |