Struct vs. Record vs. Class
Struct (struct)
- Value Type - A struct is a value type, meaning it is stored on the stack (or inline within other types) and is passed by value.
- Lightweight - Typically used for small, simple data structures that are meant to represent a single value (e.g., Point, Rectangle).
- No Inheritance - structs do not support inheritance (other than implementing interfaces). However, they can have constructors, methods, fields, properties, and events.
- Immutability - Often used for immutable data structures, though they can be mutable as well.
- Performance - They generally have better performance for small objects because they avoid heap allocation and garbage collection overhead.
public struct Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; Y = y; } }
Record (record)
- Reference Type - A record is a reference type, stored on the heap and passed by reference.
- Immutability - By default, records are immutable, though they can be made mutable. They are designed for data storage with a focus on immutability.
- Value Equality - Records provide built-in value equality, meaning two record instances are considered equal if their properties have the same values, unlike classes where equality is based on reference unless overridden.
- Primary Constructors - Records can define their properties directly in a concise manner using a primary constructor.
- Inheritance - Records support inheritance like classes.
public record Point(int X, int Y);
Class (class)
- Reference Type - A class is a reference type, stored on the heap, and passed by reference.
- Mutable by Default - Unlike records, classes are typically mutable.
- Inheritance - Classes support full inheritance, allowing for the creation of complex object hierarchies.
- Encapsulation - Classes are designed for encapsulating data and behavior, making them ideal for business logic and complex data models.
- Equality - By default, equality for classes is reference-based, but it can be overridden to implement value equality.
public class Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; Y = y; } public override bool Equals(object obj) { if (obj is Point other) { return X == other.X && Y == other.Y; } return false; } public override int GetHashCode() => (X, Y).GetHashCode(); }
When to Use Which:
- Struct - Use when you have small, lightweight objects that represent a single value and where performance is critical (e.g., mathematical points, coordinates).
- Record - Use when you need to create immutable data structures with built-in value equality, especially for DTOs (Data Transfer Objects) or entities in functional programming.
- Class - Use when you need complex objects with encapsulated state and behavior, or when you require inheritance and polymorphism.