Generics
Generics parameterize a type or method by a type argument T, so one definition like List<T> works for any type while staying strongly typed. This removes the main pain of object containers — casts on read and boxing of value types — and moves type checking to compile time.
The key idea that sets C# apart from Java: C# generics are reified. The CLR keeps the real type argument at runtime, and the JIT specializes the code per value type, so List<int> holds real ints with no boxing, and T can be recovered via reflection. The whole topic builds around this: generic methods with type inference, where constraints, generic collections, the IEnumerable<T> contract as the basis of lazy sequences, and the default(T) operator for the "zero" value of an open type. The full map lives in the layers below.
Topic map
- Generics — parameterizing by
T, type safety without boxing, runtime reification versus Java erasure. - Generic methods — a method's own type parameters, inferring
Tfrom arguments, a generic method in a non-generic class. - Generic constraints —
where T:narrows allowed arguments and unlocks member calls;class,struct,new(), a base class, an interface,notnull. - Generic collections —
List<T>,Dictionary<TKey,TValue>,HashSet<T>: one known type, no boxing, unlikeArrayList. - IEnumerable — the
GetEnumeratorcontract, forward-only read iteration, the basis of LINQ deferred execution andyield return. - The default operator —
default(T)yields the zero value:null,0/false, or a zeroed struct; why an openTneeds it.
Common traps
| Mistake | Consequence |
|---|---|
Treating generics as object containers with sugar | Missing compile-time type checking; List<int> does NOT box its elements |
Thinking C# erases T like Java | In C# T is reified and recoverable via reflection; the JIT specializes per value type |
Always spelling out <T> at the call site | The compiler usually infers T from the arguments; explicit <T> is needed only when it cannot |
| Assuming only a generic class can host a generic method | A plain class can declare one too |
Thinking where is checked at runtime | Constraints are checked by the compiler up front; without them the body treats T only as object |
Expecting default(T) to always be null | For value types it is 0/false/a zeroed struct, not null |
Thinking default(T) calls a constructor | It only zeroes memory, running no constructor or field initializers |
Interview relevance
Generics are a mandatory topic at middle level and above. A candidate who explains why List<int> does not box its elements and how C# reification differs from Java erasure shows understanding of the runtime, not just syntax.
Typical checks:
- Why generics over
object: compile-time type safety, reuse, no boxing. - Reification in C# versus erasure in Java, and the role of JIT specialization.
- A generic method and inferring the type from arguments.
- What
whereconstraints do and which kinds exist. - The
IEnumerable<T>contract and deferred (lazy) execution. - What
default(T)yields and why it is not alwaysnull.
Common wrong answer: "Generics are just object with nicer syntax." That opens the discussion of compile-time type checking, no boxing of value types, and the fact that T in C# survives to runtime and is recoverable via reflection.