C# Intermediate: OOP, Interfaces & Events

Lesson 3 of 7

Generics

A generic type or method works with any type, decided when it's used, without giving up type safety or duplicating code.

class Stack<T>
{
    private List<T> items = new List<T>();

    public void Push(T item) => items.Add(item);

    public T Pop()
    {
        T last = items[^1];
        items.RemoveAt(items.Count - 1);
        return last;
    }
}

var numbers = new Stack<int>();
numbers.Push(5);
numbers.Push(10);
Console.WriteLine(numbers.Pop()); // 10

var names = new Stack<string>();
names.Push("Ada");

The pieces

  • <T> is a type parameter, a placeholder that gets filled in with a real type (int, string, ...) when the class or method is used.
  • Stack<int> and Stack<string> are both backed by the same Stack<T> code, but the compiler enforces that a Stack<int> only ever holds ints.
  • Generic methods work the same way: T Max<T>(T a, T b) where T : IComparable<T>.
  • where T : SomeConstraint restricts what T can be, e.g. where T : class (reference types only) or where T : IDamageable.

Why not just use object?

A non-generic collection typed as object would compile but let you push mismatched types, and would need a cast (with a runtime risk) every time you read a value out. Generics catch that mistake at compile time instead.

📝 Generics Quiz

Passing score: 70%
  1. 1.What does <T> represent in a generic class like Stack<T>?

  2. 2.A clause like where T : IComparable<T> is called a type ____.

  3. 3.Generics catch type mismatches at compile time instead of at runtime.