Mutable objects causing threading issues? C# 9+ records provide immutable data structures with built-in value semantics.
Records vs Classes: When to Use Each
// Use RECORDS for: // 1. Immutable data transfer objects (DTOs) // 2. Value objects in domain-driven design // 3. Configuration objects // 4. API request/response models // 5. Event objects in event sourcing // Use CLASSES for: // 1. Entities with identity and mutation // 2. Services with behavior // 3. Complex objects with inheritance hierarchies // 4. Objects needing custom equality semantics // 5. Framework base classes // Example: Record for API response public record ApiResponse( T Data, bool Success, string Message, DateTime Timestamp = default) { public DateTime Timestamp { get; init; } = Timestamp == default ? DateTime.UtcNow : Timestamp; } // Usage: var response = new ApiResponse ( Data: product, Success: true, Message: "Product retrieved successfully"); // Immutable - cannot modify after creation // Value equality - two responses with same data are equal // Built-in ToString() with property values // Deconstruction support
Advanced Record Patterns:
// Positional record (immutable by default)
public record Person(
string FirstName,
string LastName,
int Age);
// With non-positional properties
public record Employee : Person
{
public string EmployeeId { get; init; }
public decimal Salary { get; init; }
public Department Department { get; init; }
public Employee(
string firstName,
string lastName,
int age,
string employeeId,
decimal salary,
Department department)
: base(firstName, lastName, age)
{
EmployeeId = employeeId;
Salary = salary;
Department = department;
}
}
// Record struct (C# 10+)
public readonly record struct Point(
double X,
double Y)
{
public double DistanceFromOrigin => Math.Sqrt(X * X + Y * Y);
}
// With validation in init-only setters
public record OrderItem
{
private int _quantity;
private decimal _price;
public int Quantity
{
get => _quantity;
init
{
if (value <= 0)
throw new ArgumentException("Quantity must be positive");
_quantity = value;
}
}
public decimal Price
{
get => _price;
init
{
if (value < 0)
throw new ArgumentException("Price cannot be negative");
_price = value;
}
}
public decimal Total => Quantity * Price;
}
