Using Records in C#
Introduced in C# 9.0 as part of .NET 5, records are a type of reference class that is specifically designed to be immutable and to provide value-based equality semantics. They are intended to be used primarily for encapsulating data rather than behavior, making them ideal for data-centric applications. This article explores what records are, how they are used in C#, and provides practical examples of their implementation.
What is a Record?
A record in C# is a reference type that makes it easier to create immutable objects. Unlike classes, records use value-based equality logic—meaning two record objects are considered equal if all their properties contain the same values, not merely if they refer to the same object.
Records are particularly useful for patterns where data is not meant to change after it's created, such as with data transfer objects (DTOs) or entities in domain-driven design.
Features of Records
- Immutability: By default, records are immutable. Any modification of a record instance results in a new instance.
- Value-based Equality: Automatically implemented equality checks based on the values of properties.
- With-expressions: Syntactic support for non-destructive mutation, allowing you to create a new record with altered properties based on an existing record.
- Conciseness: Records reduce boilerplate code, allowing for more succinct and readable definitions.
Example of a Record in C#
Defining a Simple Record
Here is how you can define a record in C#:
public record Person(string FirstName, string LastName);
This record Person has two properties: FirstName and LastName. Records can be declared in a very concise manner, automatically creating constructor, properties, and methods for equality checks.
Creating and Using Records
var person1 = new Person("John", "Doe");
var person2 = new Person("Jane", "Smith");
var person3 = new Person("John", "Doe");
In this example, person1 and person3 are considered equal because their properties match, despite being different instances.
Using With-Expressions
Records support with-expressions, which create a new record instance while changing some of the properties:
var person4 = person1 with { FirstName = "James" };
person4 is a new instance where the FirstName has been changed to "James", but the LastName remains the same as person1.
When to Use Records
Records are particularly beneficial in the following scenarios:
- Functional Programming: Records fit well in functional programming paradigms where immutability is a key principle.
- Data Modeling: Perfect for modeling data that doesn't change after creation, such as read-only data retrieved from a database.
- Concurrency: Immutable types like records are safer to use in concurrent or multi-threaded environments as they help avoid issues related to state corruption.
- Simplifying Code: Reducing boilerplate code for classes that primarily carry data.
Conclusion
Records in C# provide a robust, immutable data structure with value-based equality and built-in support for non-destructive mutations. They simplify the definition of data models, improve the clarity of your code, and enhance the safety of your applications, particularly in multi-threaded scenarios. By utilizing records, developers can ensure that their applications are built on a solid foundation of immutable and easy-to-manage data structures.