Introduction
In modern C# development, record types have become a powerful feature for writing clean, readable, and maintainable code. Introduced in C# 9, records are mainly used for storing data in an immutable way.
If you have worked with classes before, you might wonder why record types were introduced. The answer is simple: records are designed for scenarios where you want to represent data, not behavior.
In this article, we will understand what C# record types are, how they work, and when you should use them in real-world applications.
What is a Record Type in C#?
A record is a special type in C# that is used to define immutable data models.
Unlike classes, records are value-based, meaning they compare objects based on their data rather than memory reference.
Key Features of Record Types
Example of a Record
public record Person(string Name, int Age);
class Program
{
static void Main()
{
var person1 = new Person("John", 30);
var person2 = new Person("John", 30);
Console.WriteLine(person1 == person2); // True
}
}
Here, both objects are considered equal because their values are the same.
Record vs Class in C#
| Feature | Class | Record |
|---|
| Equality | Reference-based | Value-based |
| Mutability | Mutable by default | Immutable by default |
| Use Case | Behavior + Data | Data-focused |
| Syntax | More verbose | Concise |
How Record Types Work Internally
When you create a record:
The compiler generates methods like Equals(), GetHashCode(), and ToString()
It creates value-based comparison logic
It supports non-destructive mutation using 'with' keyword
This reduces boilerplate code and improves readability.
Immutable Nature of Records
By default, records are immutable, meaning their values cannot be changed after creation.
public record Person(string Name, int Age);
var person = new Person("John", 30);
// person.Name = "Mike"; // Not allowed
This helps in building safer and predictable applications.
Using 'with' Expression in Records
Records support cloning with modification using the 'with' keyword.
var person1 = new Person("John", 30);
var person2 = person1 with { Age = 35 };
Console.WriteLine(person2);
This creates a new object instead of modifying the existing one.
Types of Records in C#
1. Positional Records
Defined using a compact syntax:
public record Person(string Name, int Age);
2. Non-Positional Records
Defined like classes:
public record Person
{
public string Name { get; init; }
public int Age { get; init; }
}
3. Record Structs (C# 10+)
Records can also be value types:
public record struct Point(int X, int Y);
When to Use Record Types in C#
1. Data Transfer Objects (DTOs)
Records are perfect for DTOs where you only need to transfer data between layers.
2. Immutable Data Models
Use records when your data should not change after creation.
3. Value-Based Comparisons
If you need equality based on values, records are the best choice.
4. API Responses
Records are commonly used in Web APIs for request and response models.
5. Functional Programming Style
Records support immutability, which is important in functional programming.
When NOT to Use Records
When you need mutable objects
When behavior is more important than data
When performance is critical and struct is a better fit
Real-World Example
Let’s consider an API response model:
public record ApiResponse(string Status, string Message);
var response1 = new ApiResponse("Success", "Data loaded");
var response2 = new ApiResponse("Success", "Data loaded");
Console.WriteLine(response1 == response2); // True
This makes records ideal for backend and API development.
Advantages of Record Types
Common Mistakes Developers Make
Using records for complex business logic
Assuming records are always immutable (can be changed with init or mutable properties)
Not understanding value-based equality
Best Practices
Use records for data-only objects
Keep records small and focused
Prefer positional records for simple use cases
Avoid mixing business logic inside records
Summary
C# record types are a modern and powerful feature designed for data-centric programming. They provide value-based equality, immutability, and a clean syntax, making them ideal for DTOs, API models, and functional-style programming. By understanding when to use records and when not to, you can write cleaner, more efficient, and maintainable C# applications.