Class vs Record vs Struct in C#: Understanding the Differences
Choosing between class, record, and struct isn’t just style — it changes allocation, equality, copying, immutability defaults, and how your types behave in collections and APIs.
Here’s the practical breakdown 👇
1) The mental model
✅ class
- Reference type (usually allocated on the managed heap)
- Variables hold a reference to the same object
- Best for mutable, identity-based objects (entities, services, complex graphs)
✅ record
- Primarily about value-based equality and with-expressions
- Can be reference type (
record) or value type (record struct) - Best for data models where equality should be based on contents
✅ struct
- Value type (stored inline in arrays/fields; may be stack-allocated in some cases)
- Assignments create a copy
- Best for small, immutable-ish, performance-sensitive data (points, money, IDs)
2) Equality: the biggest “gotcha”
class → reference equality by default
Two objects with same data are not equal unless you override equality.
record → value equality by default
Two records with the same data are equal (by generated Equals/GetHashCode).
struct → value equality, but…
Struct equality exists, but:
- can be slower depending on fields
- mutable structs can create chaos in collections
3) Copy semantics: who gets copied?
class / record (reference type)
var a = new Person("Diego"); var b = a; b.Name = "Other"; Console.WriteLine(a.Name); // "Other" (same instance)
struct / record struct (value type)
var a = new Point(1, 2); var b = a; b = b with { X = 99 }; Console.WriteLine(a.X); // 1 (copied)
4) Immutability defaults (and what people assume)
class
Mutable by convention (unless you enforce immutability manually)
record
Encourages immutability:
public record Person(string Name, int Age);
- init-only properties
withcloning is first-class
struct
Can be immutable, but you must design it that way.
Rule of thumb: if you use structs, prefer readonly struct.
5) When to use what (real-world guidance)
Use class when:
✅ you model entities with identity (e.g., User, Order)
✅ you need polymorphism, inheritance, large graphs
✅ the object is mutable by design
Use record when:
✅ you pass data around (DTOs, messages, query results)
✅ you want value equality and easy cloning
✅ you want clean “data-centric” code
Use struct when:
✅ the type is small (commonly under ~16–32 bytes)
✅ it’s immutable and frequently created
✅ you want to reduce allocations in hot paths
6) Quick cheat sheet
- Identity matters? →
class - Data + value equality matters? →
record - Tiny value, performance, avoid allocations? →
readonly struct/record struct
7) Common pitfalls
❌ Mutable structs
They copy silently and can break expectations.
❌ Large structs
Copying big structs repeatedly can be slower than a class reference.
❌ Using record for entities
Record’s value equality can be wrong for identity-based domain entities.
Takeaway
- Class = identity + reference behavior
- Record = data + value equality + great ergonomics
- Struct = value semantics + performance (when designed carefully)
