What is boxing and unboxing in C#?

C# Type System Intermediate 1–2 Yrs2–3 Yrs3–5 Yrs Conceptual 2 min read

Quick Answer

Boxing is wrapping a value type in an object (or interface) reference so it can live on the heap — it happens implicitly when you assign an int to an object. Unboxing is the explicit cast back to the value type. Both cost a heap allocation / copy, so boxing in hot paths and large loops is a performance problem.

Boxing is when a value type gets wrapped in an object reference and moved to the heap — it happens automatically when you assign, say, an int to an object variable. Unboxing is the explicit cast back. Each one is a heap allocation and a copy, so it's cheap once and expensive in a tight loop. The classic place it used to bite people was the old non-generic collections like ArrayList, which store everything as object — that's a big reason generics were added. So the way to avoid it is to use generic collections and generic methods so the value type stays a value type.

Because every type is rooted at object, a value type sometimes has to be treated as a reference. The CLR does this by allocating a box on the heap, copying the value into it, and handing back a reference.

Where it sneaks in:

  • Non-generic collections — ArrayList, Hashtable store object, so every int you add is boxed.
  • String formatting — string.Format("{0}", 42) boxes (mitigated by interpolation improvements, but still possible).
  • Calling an interface method on a struct held as the interface type.
  • object.Equals / non-generic IComparable.

How to avoid it: use generics (List<int>, Dictionary<int,T>) so the value type is stored directly; implement IEquatable<T> on structs; prefer generic constraints over object parameters. Unboxing also throws InvalidCastException if the target type doesn't exactly match.

C# — boxing
int n = 42;
object boxed = n;        // boxing: heap allocation + copy
int back = (int)boxed;   // unboxing: explicit cast + copy

// hidden boxing in a non-generic collection
var list = new System.Collections.ArrayList();
list.Add(1);             // boxed
list.Add(2);             // boxed

// no boxing
var fast = new List<int> { 1, 2 };