Recent site activity

C# - C Sharp‎ > ‎

Generics


C# has two separate mechanisms for writing code that is reusable across different types: inheritance and generics. Whereas inheritance expresses reusability with a base type, generics express reusability with a “template” that contains “placeholder” types. Generics, when compared to  inheritance, can increase type safety and reduce casting and boxing.

Generic Types

A generic type declares type parameters—placeholder types to be filled in by the consumer of the generic type, which supplies the type arguments. Here is a generic type Stack<T>, designed to stack instances of type T. Stack<T> declares a single type parameter T:
public class  Stack<T>
{
int position;
T[] data = new T[100];
public void Push (T obj) { data[position++] = obj; }
public T Pop() { return data[--position]; }
}

We can use Stack<T> as follows:
Stack<int> stack = new Stack<int>();
stack.Push(5);
stack.Push(10);
int x = stack.Pop(); // x is 10
int y = stack.Pop(); // y is 5

Stack<int> fills in the type parameter T with the type argument int, implicitly creating a type on the fly (the synthesis occurs at runtime). Stack<int> effectively has the following definition (substitutions appear in bold, with the class name hashed out to avoid confusion):
public class ###
{
int position;
int[] data;
public void Push (int obj) { data[position++] = obj; }
public int Pop() { return data[--position]; }
}

Technically, we say that Stack<T> is an open type, whereas Stack<int> is a closed type. At runtime, all generic type instances are closed—with the placeholder types filled in. This means that the following statement is illegal:
var stack = new Stack<T>(); // Illegal: What is T?

unless inside a class or method which itself defines T as a type parameter:
public class Stack<T>
{
...
public Stack<T> Clone()
{
Stack<T> clone = new Stack<T>(); // Legal
}
}