CodeOath
← All posts
C#65 min total · 17 parts

C# Fundamentals: Value Types, Reference Types, Boxing, and the Type System

Contents — Part 2 of 17: Value Types Copy, Reference Types Share
Part 2 of 17 · ~2 min

Value Types Copy, Reference Types Share

Diagram comparing value types copying data on the stack versus reference types sharing one object on the heap

int, bool, double, DateTime, and any struct are value types — assigning one copies the actual data. class instances are reference types — assigning one copies a reference to the same object, not the object itself.

int a = 5;
int b = a;
b = 10;
Console.WriteLine(a); // 5 — b holds its own independent copy

class Point { public int X; }
Point p1 = new Point { X = 5 };
Point p2 = p1;
p2.X = 10;
Console.WriteLine(p1.X); // 10 — p1 and p2 point to the same object

This is the single most common source of "why did changing this also change that" bugs — and, in the other direction, "why didn't changing this affect that" bugs when someone expects reference semantics from a value type (or vice versa).

Method parameters follow the same rule by default: passing a value type copies it into the method, so changes inside the method don't affect the caller's variable — unless you explicitly opt in with ref or out (covered in depth later):

void Increment(ref int x) { x++; }

int n = 5;
Increment(ref n);
Console.WriteLine(n); // 6 — ref makes the parameter an alias for the caller's variable

Passing a reference type parameter, by contrast, copies the reference — so mutating the object it points to is visible to the caller, but reassigning the parameter itself to a new object is not:

void Rename(Point p) { p.X = 99; }        // mutates the shared object — caller sees it
void Replace(Point p) { p = new Point(); } // reassigns the local copy of the reference — caller does not see it

var point = new Point { X = 1 };
Rename(point);
Console.WriteLine(point.X); // 99

Replace(point);
Console.WriteLine(point.X); // still 99 — Replace only changed its own local reference