C#64 min total · 17 parts
C# Fundamentals: Value Types, Reference Types, Boxing, and the Type System
Part 10 of 17 · ~2 min
Arrays and Collections Are Reference Types
A warehouse runs an end-of-day count and stores the result as a snapshot array:
StockCount[] endOfDay = TakeSnapshot(); // one StockCount per SKU, at closing time
StockCount[] forAudit = endOfDay;
forAudit[0] = new StockCount { Sku = endOfDay[0].Sku, OnHand = 0 };
Console.WriteLine(endOfDay[0].OnHand); // 0 — same array object, both names see the edit
Here's the twist: an array itself is a reference type, full stop, no matter what it's an array of. StockCount[] is holding value types, but the array object wrapping them still lives on the heap like any other object, and what varies is only whether its elements sit inline in that block (for a value-type array) or as further references out to other objects (for a reference-type array). Assigning forAudit = endOfDay copies the handle to that one array object — nothing about the elements gets duplicated — which is the "value types copy" rule from the first chapter turning around and biting people from the opposite direction: the outer array is shared even though what it's full of copies on its own.
Getting a genuinely independent array takes an explicit copy:
StockCount[] trueCopy = (StockCount[])endOfDay.Clone(); // a separate array, separate storage
StockCount[] trueCopy2 = endOfDay.ToArray(); // LINQ — also separate
Array.Copy(endOfDay, trueCopy2, endOfDay.Length); // another way to get one
That's genuine independence for an array of StockCount structs, because cloning duplicates the value data itself. Do the same clone on Shipment[] instead, and only the array of references gets duplicated — every Shipment object those references point to is still the exact same shared object in both arrays:
Shipment[] active = GetActiveShipments();
Shipment[] snapshot = (Shipment[])active.Clone();
snapshot[0].PickedSkus.Add("LATE-ADD");
Console.WriteLine(active[0].PickedSkus.Count); // reflects the change too — same underlying Shipment object
That's the whole definition of a shallow copy in one sentence: it duplicates the box, never what's sitting inside the box. "I already cloned it" is exactly the assumption that gets punctured the moment someone mutates an object reachable through either array and watches the change show up in both.