Generics
- C# is a strongly typpe language, when using C# you should declare a type prior to storing data in it.
- Generics types to eliminate redundant code, type safety, code re-usability and performance.
- create generic interfaces, classes, methods, events and delegates.
- Generic can be defined by putting the <T> sign after the class or method name. instead of "T" you can use any word.
- Generic data type obtained at run-time by using reflection.
- Generics allow you to write a class or method that can work with any data type.
- System.Collection.Generic namespace contains Collection<T>, Dictionary<TKey, TValue>, List<T>, Queue<T>, Stack<T>
Type Safety Example
ArrayList obj = new ArrayList();
obj.Add(50);
obj.Add("Dog");
obj.Add(new TestClass());
foreach(int i in obj) Console.WriteLine(i);
//the code will compile, but run time iteration will through 'InvalidCastException' occurred when it print "Dog", bcz it
is not integer, the code will print 50.
GenericClass<int> intObj = new GenericClass<int>();
intObj.setItem(0, 50);
intObj.setItem(1, "Dog"); //compiler error, the compiler doesn't compile the code.
Performance
Generics are faster than other collections such as ArrayList. In non-generic colloection, boxing and unboxing overhead when a value type is converted to reference type and vice-versa.
ArrayList obj = new ArrayList();
obj.Add(50); //boxing- convert value type to reference type
int x= (int)obj[0]; //unboxing
GenericClass<int>, an int type is generated dynamically from the compiler, boxing and unboxing no longer occurs.
GenericClass<int> obj = new GenericClass<int>();
obj.Add(50); //No boxing
int x= obj[0]; // No unboxing
Code reuse - A Generic class can be defined once and can be instantiated with many different types.
GenericClass<int> intObj = new GenericClass<int>();
GenericClass<char> charObj = new GenericClass<char>();
Generic Class Example
using System;
using System.Collections.Generic;
namespace GenericClassApplication
{
public class GenericClass<T>
{
private T[] obj = new T[5]; // define an Array of Generic type with length 5
public T getItem(int index)
{
return obj[index];
}
public void setItem(int index, T value)
{
obj[index] = value;
}
}
class Program
{
static void Main(string[] args)
{
//instantiate generic with int
GenericClass<int> intObj = new GenericClass<int>();
for (int i = 0; i < 5; i++) intObj.setItem(i, i*2);
for (int i = 0; i < 5; i++) Console.WriteLine(intObj.getItem(i)); //0 2 4 6 8
//instantiate generic with char
GenericClass<char> charObj = new GenericClass<char>();
for (int i = 0; i < 5; i++) charObj.setItem(i, (char)(i*2));
for (int i = 0; i < 5; i++) Console.WriteLine(charObj.getItem(i));
}
}
}
Generic Methods Example
using System;
using System.Collections.Generic;
namespace GenericMethodApplication
{
class Program
{
static void Swap<T>(ref T a, ref T b)
{
T temp;
temp = a;
a = b;
b = temp;
}
static void Main(string[] args)
{
int a=10, b=20; //a = 10, b = 20
Swap<int>(ref a, ref b); //a = 20, b = 10
char i = 'I', j ='J';
Swap<char>(ref i, ref j); //i = 'J', j = 'I'
}
}
}
Generic Delegates Example
using System;
using System.Collections.Generic;
delegate T GenericDelegate<T>(T n);
namespace GenericDelegateApplication
{
class DelegateClass
{
static int n = 10;
public static int Sum(int i)
{
n += i;
return n;
}
public static int Times(int i)
{
n *= i;
return n;
}
public static int getValue()
{
return n;
}
static void Main(string[] args)
{
//create delegate instances
GenericDelegate<int> gd1 = new GenericDelegate<int>(Sum);
GenericDelegate<int> gd2 = new GenericDelegate<int>(Times);
gd1(5); //calling the methods using the delegate objects,
getValue(); //15
gd2(2);
getValue(); //30
}
}
}
Boxing - Boxing is used to store value types in the garbage-collected heap. A referece type is allocated on the heap.
int i = 123;
object o = i; //implicit conversion of a value type to the reference type (object).
stack heap
i
-----
| 23 |
-----
int i=123;
o
--- -----
| |---------> |int |
--- |----|
object o =i; |123 |
-----
Unboxing - an explicit conversion from the reference type(object) to a value type. A value type is allocated on the stack
int j = int(o);
j
-----
| 23 |
-----
int j =(int)o;