Let us understand the Generics with a simple example. Here I
have implemented a stack in two different ways. A stack that can be
recollected, works in the LIFO (Last-In-First-Out) principle. If we implement a
stack that can accept any data type or object and store the same in to it, we
have to opt for an object based stack (obviously if we are not using Generics).
I have given here two code examples of a partial implementation of a stack.
The first one is an object based stack and the next a
generic stack. The object based stack would require boxing and unboxing
operations to store and return objects in and out of the stack, but the generic
stack (the one that uses C# Generics) would not. Hence, as far as performance
is concerned, the generic stack is the better choice.
The code in Listing 4 is an example of an object based
stack. Note that we can store any type of data in this stack, but we need to
perform an explicit cast in order to retrieve the right type of the object that
was stored using boxing and unboxing. This can be a significant performance
overhead.
Listing 4
using System;
using System.Collections.Generic;
using System.Text;
namespace Generics
{
public class CustomStack
{
const int size = 10;
private object[] register;
private int count = 0;
private CustomStack()
{
register = new object[size];
}
public void Push(object x)
{
if (count < size)
register[count++] = x;
}
public object Pop()
{
return register[--count];
}
static void Main(string[] args)
{
CustomStack intStack = new CustomStack();
intStack.Push(10);
int i = (int)intStack.Pop();
Console.WriteLine(i);
Console.Read();
}
}
}
When using the object based stack shown in Listing 1, you
have to box and unbox the elements in order to push and pop them in and out of
the stack resulting in a significant performance drawback. Now, Generics comes
to the rescue. It is much more flexible and removes the overhead involved in
boxing and unboxing operations that we discussed earlier as a generic type is
assigned a specific type only at runtime. The type checks are done at the
compile time itself. Hence, the generic stack in our example works much faster
compared to its non-generic counterpart. The following is the implementation of
a generic stack using C# Generics.
Listing 5
using System;
using System.Collections.Generic;
using System.Text;
namespace Generics
{
public class CustomStack<S>
{
const int size = 10;
private S[] register;
private int count = 0;
public CustomStack()
{
register = new S[size];
}
public void Push(S x)
{
if (count < size)
register[count++] = x;
}
public S Pop()
{
return register[--count];
}
}
public class Test
{
static void Main(string[] args)
{
CustomStack<int> intStack = new CustomStack<int>();
intStack.Push(10);
int i = intStack.Pop();
Console.WriteLine(i);
Console.Read();
}
}
}