🎉 Records vs Classes: When to Use Them and Why Records Are Cooler! 😎💻
Records were introduced with C# 9, and they offer many benefits due to their immutable nature and value-based equality checks. However, they are still not widely used in many projects. In this article, we'll explore where records can be useful and how they differ from classes. Are there specific scenarios where records are more advantageous? Let's dive into these questions and examine the benefits of using records.
🚀 Class vs Record Comparison
🏷️ Class Structure:
Let's take a look at a classic class structure that's been widely used in C#. Below is the Employee class, which holds information about an employee. This structure is mutable, meaning the property values can be modified after initialization.
public class Employee
{
public int EmployeeID { get; set; }
public string FullName { get; set; }
public string Position { get; set; }
public Employee(int employeeID, string fullName, string position)
{
EmployeeID = employeeID;
FullName = fullName;
Position = position;
}
}In this class, properties can be updated after the object is created. For example, the employee’s position can be changed later.
📋 Record Structure:
Records, on the other hand, are immutable, meaning that once defined, their properties cannot be changed. Below is the same Employee structure defined as a record:
public record EmployeeRecord(int EmployeeID, string FullName, string Position);This structure is defined in a single line, improving readability and ensuring immutability. Once an EmployeeRecord is created, its property values cannot be modified.
🎯 Class vs Record: Key Differences
1️⃣ Mutability:
Classes are mutable by default, meaning their values can be changed after instantiation. However, Records are immutable, meaning their properties cannot be modified after assignment.
In the example below, the employee object is mutable, but the employeeRecord is immutable, so attempting to change its values will cause an error:
var employee = new Employee(1, "John Doe", "Engineer");
employee.Position = "Senior Engineer"; // This can be updated.
var employeeRecord = new EmployeeRecord(1, "John Doe", "Engineer");
// employeeRecord.Position = "Senior Engineer"; // This will throw an error, as Records are immutable.This feature ensures data integrity in scenarios where the data must remain unchanged.
2️⃣ Use Cases:
The immutable nature of records makes them highly useful in specific scenarios. Here are some common use cases for records:
API Responses: When returning data from an API, immutability ensures that the returned data is not modified accidentally. For example:
public record ApiResponse(bool IsSuccess, string Message, object Data);This structure ensures that the API response remains unchanged after being generated.
DTO (Data Transfer Object): Immutable structures are important when transferring data between different layers of an application. Records provide a secure way to handle this data:
public record OrderDTO(int OrderID, string ProductName, int Quantity, decimal Price);Config Structures: Configuration data is usually static and should not be altered. Records are ideal for storing configuration information:
public record AppConfig(string DatabaseConnectionString, int CacheTimeout, bool IsDebugMode);3️⃣ Value Equality:
Classes perform equality checks based on reference. This means two class instances are considered equal only if they reference the same object in memory. Records, on the other hand, perform value-based equality checks. This means that two records with the same data are considered equal, even if they are different instances.
In the example below, the two CarClass objects will return false because their references are different, while the two CarRecord objects will return true because their values are the same:
public class CarClass
{
public string Model { get; set; }
public int Year { get; set; }
public CarClass(string model, int year)
{
Model = model;
Year = year;
}
}
public record CarRecord(string Model, int Year);
var car1 = new CarClass("Toyota", 2020);
var car2 = new CarClass("Toyota", 2020);
Console.WriteLine(car1.Equals(car2)); // False
var record1 = new CarRecord("Toyota", 2020);
var record2 = new CarRecord("Toyota", 2020);
Console.WriteLine(record1.Equals(record2)); // True4️⃣ Where Can Records Be Used?
Cache Keys: Cache keys are typically immutable and should not change after being created. Records are perfect for this use case:
public record CacheKey(string Key, DateTime Expiration);Logs: Using records for logs ensures that log data remains unchanged and reliable:
public record ActionLog(DateTime Timestamp, string ActionType, int UserID);Database Entities: When comparing database entities, records are a great fit because they provide value-based comparison. This ensures that operations like updates or no-ops are only performed when necessary.
5️⃣ Cloning with Records:
Records can be easily cloned using the with keyword. For example, the following Laptop record can be copied and updated:
public record Laptop(string Brand, string Model, decimal Price);
var laptop = new Laptop("Dell", "XPS 15", 1500m);
var newLaptop = laptop with { Model = "XPS 13" };
Console.WriteLine(newLaptop);
// Output: Laptop { Brand = Dell, Model = XPS 13, Price = 1500 }This feature allows you to create modified copies of records while keeping the original data intact.
💡 Conclusion:
Records are incredibly useful in scenarios where immutability is important. They provide great advantages for handling API responses, configuration data, log records, and DTOs. Additionally, records offer value-based equality, which makes them ideal for use in repositories or services where comparing data values is critical. The ease of cloning with the with keyword also improves code readability and reduces redundancy.


