Value Types vs. Reference Types
The problem
Assigning one variable to another, or passing a value into a method, means something different depending on whether that value is copied entirely or shared by reference — getting this wrong produces exactly the aliasing bugs (or unexpected performance costs from excessive copying) that come from assuming the wrong one.
Why now
Mutability and references already established the general copy-versus-share distinction; .NET makes that distinction unusually explicit and pervasive — every type in C# is declared as a struct (value type) or a class (reference type), a first-class language-level choice rather than an implicit rule based on the value's kind.
Mental model
A value type (struct, int, bool) is copied in full on assignment or when passed to a method — two variables holding a value type never share the same underlying data. A reference type (class) behaves like mutability-and-references already described for objects: the variable holds a pointer to shared data on the heap, so copying the variable copies the pointer, not the data. Choosing struct versus class in C# is choosing this behavior deliberately, not discovering it after the fact.
Requires
- Mutability & ReferencesProgramming Fundamentals
This topic is exactly the copy-versus-share distinction already established there, made into an explicit, declared choice (struct vs. class) instead of an implicit rule tied to a value's kind — you need the underlying concept before its more rigid, explicit .NET expression is meaningful.
- The CLR & Managed Execution.NET Internals
Where a value lives (stack for most value types, heap for reference types) and how the CLR handles copying versus pointer-sharing during method calls is a direct consequence of the CLR's memory management already established generally.
Used in
- Choosing struct versus class when designing a new type in C#
- Performance-sensitive code, where avoiding unnecessary heap allocation via structs matters (games, high-throughput services)
- Explaining unexpected behavior when a struct is modified inside a method but the caller's copy appears unchanged
- Records and readonly structs as more recent C# features building on this same distinction
Projects
- Write a struct and a class with identical fields, pass each into a method that modifies a field, and demonstrate that the struct's caller sees no change while the class's caller does
- Benchmark allocating a large number of small structs versus small classes in a tight loop, and explain the performance difference in terms of stack versus heap allocation
Examples
- Passing a struct into a method and modifying a field inside that method leaves the caller's original copy completely untouched — the method received a full copy, not a reference
- Two variables both holding the same class instance and one setting a field via one variable is visible through the other, because both point to the same heap object — the identical aliasing behavior mutability-and-references already covers
Resources
Mastery checklist
- I can predict whether modifying a struct or class inside a method affects the caller's original value
- I can explain where value types and reference types typically live in memory
- I can choose struct versus class appropriately for a new type based on its intended usage
- I can explain a bug caused by assuming reference semantics for a value type or vice versa