When designing data models in C#, the choice between class, struct, and record, can significantly impact performance, and memory usage.
But what makes record struct such a good fit for lightweight models compared to classes?
Classes: The Default Choice
By default, most developers reach for class. Classes are reference types:
- They live on the heap.
- Variables hold references (pointers) to objects.
- Garbage Collection (GC) must clean them up when no longer used.
Advantage: Good for large, complex objects that are shared or mutated.
Disadvantage: Overkill for small, short-lived, immutable data models.
Structs
A struct is a value type:
- Allocated on the stack.
- Copied by value, not reference.
- Faster for small, short-lived objects.
- No GC overhead for stack allocations.
Advantage: Ideal for lightweight data carriers.
Disadvantage: But normal struct lacks the immutability and equality benefits of record.
Records
- A reference type.
- Record classes behave similarly to regular classes in terms of memory allocation (on the heap) and assignment (reference copying).
- Value-based equality (== compares properties, not references).
public record Point(int X, int Y);
var p1 = new Point(5, 10);
var p2 = new Point(5, 10);
var p3 = new Point(10, 20);
Console.WriteLine(p1 == p2); // True (same values)
Console.WriteLine(p1 == p3); // False (different values)
// For classes:
public class PointClass
{
public int X { get; init; }
public int Y { get; init; }
}
var c1 = new PointClass { X = 5, Y = 10 };
var c2 = new PointClass { X = 5, Y = 10 };
Console.WriteLine(c1 == c2); // False (different references)
Record Struct : The Best of Both Worlds
Combines the performance of a struct (stack-allocated, lightweight).
With the features of a record (immutability, value equality, with expressions).
public readonly record struct Point(int X, int Y);
var p1 = new Point(10, 20);
var p2 = new Point(10, 20);
// Value equality
Console.WriteLine(p1 == p2); // True
// With-expression works
var p3 = p1 with { X = 30 };
Console.WriteLine(p3); // Point { X = 30, Y = 20 }
This makes record struct perfect for lightweight models.
When to Use Record Struct
Use record struct when:
- You need small, immutable, value-like models.
- You care about low memory and avoiding heap/GC overhead.
Stick to class when:
- Objects are large, complex, or mutable.
- You need shared instances.
Top comments (0)