📦 Record Types = Immutable Data
Mutable data structures cause bugs. Record types provide immutable, value-based data with value semantics.
📝 Record Syntax
// Basic Record
public record User(string Name, int Age, string Email);
// Usage
var user = new User("John Doe", 30, "john@example.com");
var name = user.Name; // Read-only
// With Expression (Non-destructive mutation)
var updatedUser = user with { Age = 31 };
// Record with Methods
public record Product(string Name, decimal Price, string Category)
{
public decimal WithDiscount(decimal discountPercent)
=> Price - (Price * discountPercent / 100);
public override string ToString()
=> $"{Name} ({Category}) - ${Price}";
}
// Record Inheritance
public record Person(string Name, string Email);
public record Customer(string Name, string Email, string CustomerId) : Person(Name, Email);
🎯 Advanced Record Patterns
// Positional vs Nominal Records
// Positional (Primary Constructor)
public record Order(int Id, DateTime OrderDate, decimal Total);
// Nominal (Explicit Properties)
public record Customer
{
public string FirstName { get; init; }
public string LastName { get; init; }
public string FullName => $"{FirstName} {LastName}";
}
// Record with Validation
public record ValidatedUser
{
public string Name { get; init; }
public int Age { get; init; }
public ValidatedUser(string name, int age)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be empty");
if (age < 0 || age > 120)
throw new ArgumentException("Invalid age");
Name = name;
Age = age;
}
}
// Records in Collections
var users = new List<User>
{
new User("Alice", 25, "alice@example.com"),
new User("Bob", 30, "bob@example.com")
};
// Equality with Records
var user1 = new User("John", 30, "john@example.com");
var user2 = new User("John", 30, "john@example.com");
Console.WriteLine(user1 == user2); // True (Value equality)
// Records as DTOs
public record CreateUserRequest(string Name, string Email, int Age);
public record UpdateUserRequest(int Id, string Name, string Email);
💡 Record Best Practices
- Use records for immutable DTOs
- Use with expressions for updates
- Implement validation in constructors
- Use records for value-based data
- Prefer records over classes for data containers
Records simplify data modeling in C#. They provide immutability and value semantics with minimal code.
