Introduction
In this article, we will understand record types in C# 10. The Record types are introduced in C# 9. With C# 10, Microsoft has introduced some changes to make coding simple and easy. We will look at these changes along with understanding record type.
Immutable properties
Before understanding Record types, we need to understand what immutable properties are.
Immutable properties are the properties that do not allow assignment after the initialization of the types. Below is the syntax for defining Immutable properties.
Public string FirstName { get; init;}
Prerequisites
To use features described in this article, we need to have below Prerequisites
- Visual Studio 2022
- Project with Target framework .Net 6.
Record Types
Record types are the value type or reference type object which has built in support for immutable properties. We can create record types with a class or with structures. In C# 10, Microsoft added support for declaring records with the positional declaration.
Let’s see how to declare a record with positional syntax.
Record Class
Positional parameters syntax
public record Employee(string EmployeeId, string FirstName, string LastName);
Initializing object
Employee employee = new("E001", "John", "Deo");
Standard property syntax
public record Employee
{
Public string EmployeeId {get; init;}
Public string FirstName {get; init;}
Public string LastName {get; init;}
}
Initializing object
Employee employee = new Employee()
{
EmployeeId = "E001",
FirstName = "John",
LastName = "Deo"
};
Record Structures
Positional parameters syntax
public readonly record struct Employee(string EmployeeId, string FirstName, string LastName);
Initializing object
Employee employee = new("E001", "John", "Deo");
Standard property syntax
public readonly record struct Employee
{
public string EmployeeId {get; init;}
public string FirstName {get; init;}
public string LastName {get; init;}
}
Initializing object
Employee employess = new Employee()
{
EmployeeId = "E001",
FirstName = "John",
LastName = "Deo"
};
By default, all the members of record need to be immutable but in exceptional cases, we can add mutable members also to Record with the below syntax
Record Class
Positional parameters syntax
public record Employee(string EmployeeId, string FirstName, string LastName)
{
public string Designation {get; set;}
}
Initializing object
Employee employee = new("E001", "John", "Deo") { Designation = "Software Engineer" };
Standard property syntax
public record Employee
{
public string EmployeeId {get; init;}
public string FirstName {get; init;}
public string LastName {get; init;}
public string Designation {get; set;}
}
Initializing object
Employee employee = new Employee()
{
EmployeeId = "E001",
FirstName = "John",
LastName = "Deo",
Designation = "Software Engineer"
};
The record structs can also be mutable, but it does not support mixed syntax.
Positional parameters syntax
public record struct Employee(string EmployeeId, string FirstName, string LastName, string Designation);
Initializing object
Employee employee = new("E001", "John", "Deo", "Software Engineer");
Standard property syntax
public record struct Employee
{
Public string EmployeeId {get; init;}
Public string FirstName {get; init;}
Public string LastName {get; init;}
Public string Designation {get; set;}
}
Initializing object
Employee employee = new Employee
{
EmployeeId = "E001",
FirstName = "John",
LastName = "Deo",
Designation = "Software Engineer"
};
Benefits of using record types
- Build-in support for immutability with positional syntax.
- Built-in support for formatting for display.
- Support for Non-destructive mutation.
- Support for inheritance with record classes.
Build-in support for immutability
The record has built-in support for immutability. By default, all properties are defined with init. So they can’t be changed after initialization.
Built-in support for formatting for display
The record types have built-in support for ToString() method. Here ToString() method prints the names and values of public properties and fields as below.
<record type name> { <property name> = <value>, <property name> = <value>, ...}
Example:
Employee employee1 = new("E001", "John", "Deo");
Console.WriteLine(employee1);
// output: Employee { EmployeeId = E001, FirstName = John, LastName = Deo }
As per requirement, we can tweak this behavior by overriding the ToString() method.
Support for Non-destructive mutation
By using With expressions, the record supports non-destructive mutations. When we use the With expressions to copy an existing record instance, with specified properties and fields modified.
Below is an example of the same.
public record Employee(string EmployeeId, string FirstName, string LastName);
Code in Main Method,
Employee employee1 = new("E001", "John", "Deo");
Console.WriteLine(employee1);
// output: Employee { EmployeeId = E001, FirstName = John, LastName = Deo }
Employee employee2 = employee1 with {
EmployeeId = "E002", FirstName = "Allen"
};
Console.WriteLine(employee2);
// output: Employee { EmployeeId = E002, FirstName = Allen, LastName = Deo }
Support for inheritance with record classes
The record supports inheritance with record classes. But record structs do not support inheritance. We will explore this topic in more detail in the next article.
Summary
In this article, we learned about record types, including how to declare record class and record structs and the benefits of using record types.
References
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#built-in-formatting-for-display