Generics at compile time and at runtime

1 min read
On trails:CSCOREstep 7/11

Without generics, the same logic needs a method per type. With generics it is written once, with T resolved where it is called (constraints are in genericsGenericsType parameters as placeholders, so one piece of code works for many types and stays type-safe.Opens in a new tab).

C#
T Max<T>(T a, T b) where T : IComparable<T>{    return a.CompareTo(b) > 0 ? a : b;} Max(3, 7);              // works with intMax(3.5, 2.1);          // works with doubleMax("apple", "banana"); // works with string

Against object

An object version loses type checking, needs a cast that can fail at runtime, and boxes value types. Generics keep the types known, with no casts and no boxing.

Compile time

A mismatch is a compile error. List<int>.Add("hello") does not build. The non-generic ArrayList stores object, so the same mistake compiles and throws InvalidCastException at runtime.

C#
List<int> numbers = new List<int>();numbers.Add("hello"); // COMPILE ERROR: can't add a string to a List<int> ArrayList list = new ArrayList(); // non-generic, holds objectlist.Add(5);list.Add("hello");                // compiles fineint x = (int)list[1];             // CRASH at runtime: InvalidCastException

Runtime

C# keeps generic type information at runtime (reified generics). Java erases it. List<int> is a distinct runtime type, and for value types the CLR generates a specialized version, which is why generics avoid boxing.