C#64 min total · 17 parts
C# Fundamentals: Value Types, Reference Types, Boxing, and the Type System
Part 8 of 17 · ~1 min
Boxing and Unboxing
Every stock adjustment the pick station makes gets written to an audit trail — a requirement that predates this system by several years, back when the warehouse's tooling was built entirely around System.Collections.ArrayList, long before generics existed in the language. That old audit log still exists, and feeding a StockCount into it means crossing into boxing territory: wrapping a value type in a heap-allocated object so it can sit in a collection that only knows how to hold object.
ArrayList auditTrail = new ArrayList();
var adjustment = new StockCount { Sku = "WDG-100", OnHand = 41 };
auditTrail.Add(adjustment); // boxes the struct — a new heap object wrapping a COPY of it
var replay = (StockCount)auditTrail[0]; // unboxing — copies the value back out
That box captures a snapshot, taken the instant Add ran — which is worth confirming rather than assuming, because it's the detail that actually matters here:
adjustment.OnHand = 999; // mutate the original AFTER boxing it
var reread = (StockCount)auditTrail[0];
Console.WriteLine(reread.OnHand); // 41 — the box never saw the later change
None of that comes for free — a box is a genuine heap allocation, and creating one means copying the struct's entire contents into it — and the part that trips people up is how easily it happens without anything on the line announcing it:
Console.WriteLine("adjusted: " + adjustment.OnHand); // OnHand is boxed here to be treated as an object
Every value written to auditTrail across a busy shift is its own separate heap allocation and its own bit of work for the garbage collector to clean up later — invisible in a five-line demo, and a genuine cost in a system logging thousands of adjustments a day.