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.
We can use Stack<T> as follows:
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):
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:
unless inside a class or method which itself defines T as a type parameter:
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 10int y = stack.Pop(); // y is 5Stack<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}}