What is the difference between a value type and a reference type?

C# Type System Basic Fresher1–2 Yrs2–3 Yrs Conceptual 2 min read

Quick Answer

A value type (struct, enum, int, bool, DateTime) holds its data directly; assigning or passing it copies the value. A reference type (class, interface, array, delegate, string) holds a reference to an object on the heap; assigning or passing it copies the reference, so both variables point to the same object.

A value type holds its data directly, so when you assign it or pass it to a method you get a copy — changing the copy doesn't affect the original. A reference type holds a reference to an object on the heap, so assigning it copies the reference and both variables point at the same object. Structs, enums and the built-in numeric types are value types; classes, arrays, delegates and string are reference types. The default for a value type is a zeroed value and it can't be null unless you use the nullable form like int?; the default for a reference type is null. I reach for a struct only when the data is small, immutable and value-like — otherwise a class.

Storage. Value-type instances live wherever they are declared — inline in a local (stack) or inside their containing object (heap). Reference-type objects always live on the managed heap; the variable holds a pointer.

Copy semantics.

  • var b = a; for a struct copies all fields — b is independent.
  • For a class, b and a refer to the same instance; a change through one is visible through the other.

Defaults & nullability. A value type's default is a zeroed instance (0, false); it can't be null unless wrapped as Nullable<T> (int?). A reference type's default is null.

Equality. Structs compare field-by-field by default (though you should override for performance/correctness); classes compare by reference unless Equals/== are overridden (records do this for you).

When to use a struct: small (roughly ≤ 16 bytes), immutable, short-lived, value-like data (a point, a money amount). Otherwise use a class — large structs are expensive to copy and passing them around defeats the purpose.

C# — copy semantics
struct PointS { public int X; }
class  PointC { public int X; }

var s1 = new PointS { X = 1 };
var s2 = s1;          // copy
s2.X = 99;            // s1.X is still 1

var c1 = new PointC { X = 1 };
var c2 = c1;          // same object
c2.X = 99;            // c1.X is now 99