C#64 min total · 17 parts
C# Fundamentals: Value Types, Reference Types, Boxing, and the Type System
Part 6 of 17 · ~2 min
Structs Deep Dive: When and Why to Use Them
StockCount is a struct because it's exactly the shape a struct is good at: small, representing one snapshot value rather than an ongoing identity, and — once you look closely — logically immutable. A stock count from ten minutes ago doesn't change; a new count replaces it. struct earns its keep for data like that: coordinates, a money amount, a single point-in-time reading.
There's a size ceiling worth respecting here, and it's not arbitrary: Microsoft's published guidance points to roughly 16 bytes as the point where a struct stops being an obvious win, precisely because every assignment and every pass into a method physically duplicates whatever's inside it. Two int-sized fields, nobody notices the copying. Widen that struct out and the copying cost widens right along with it:
struct WarehouseZoneStats
{
public int ZoneId;
public int ItemsScanned;
public int ItemsShipped;
public double AverageScanTimeMs;
public double ErrorRatePercent;
public long BytesLoggedToday;
public double PickerUtilization;
public double SpaceUtilization; // 8 fields — every copy duplicates all of them
}
Run this through a per-scan hot loop, copying a WarehouseZoneStats into a method on every single scan to update a live dashboard, and the "value types are cheap to copy" assumption that made struct attractive in the first place quietly stops being true — the copy cost scales with how much data is in the struct, and at eight fields it's no longer free. (The in parameter chapter below is the actual fix for passing something this size around without paying that cost on every call.)
A handful of other struct facts are worth keeping in the back of your mind. On its own, a struct simply cannot hold null — that capability gets bolted back on separately, later in this reference, by Nullable<T>. A no-argument constructor that zero-fills every field comes bundled in automatically, sitting alongside whatever constructors you write yourself, unless the C# version you're targeting is new enough to let you turn that off. And a struct is permanently barred from inheriting from anything else — no base struct, no base class — though nothing stops it from implementing as many interfaces as you like.