Records Complete Guide — C# 9.0


The latest and most awaited feature records which allow you to design immutable data types.

Photo by Expect Best from Pexels

The simplest way to imagine records as immutable classes. Feature-wise, they resemble tuples. In other words, custom tuples with properties and immutability.

Consider the following example of a record which captures sign up details like first name, last name, and email address.

Record syntax

Records are specialized classes.

public record SignUp(
   string firstName,
   string lastName,
   string Email

Above record is identical to below class definition

As described above, the record and the class variants are almost identical. The record gives more enhanced functional behaviour.

What’s common between record & class?

  1. Constructor

  2. Immutability

  3. Copy semantics

What’s unique about records?

  1. Record equality works on content, whereas class equality works on object definition.

  2. Records provide a GetHashCode() implementation is that it is based on record content.

  3. Record ToString() is overridden to display record properties.

Code example to illustrate differences

Below example illustrate record equality works on content, whereas class equality works on object definition.


Below output shows that records are equals whereas two different class objects are not equal using “==” operator.

Records equality: True
Class equality: False

Different Record syntax

There are various designs for declaring records for diverse use cases.

One liner syntax

The first pattern is the easiest one, a one-liner but offers the least flexibility. It’s good for records with a small number of required properties.

Here is the SignUp record, shown earlier, as an example of this pattern.

public record SignUp(
   string firstName,
   string lastName,
   string Email

It follows the requirements of a constructor with parameters.

var SignUp = new SignUp("sukhpinder", "singh", "email");

Target typing syntax

SignUp signup= new("sukhpinder", "singh", "email");

Syntax with optional parameters

The below syntax specifies firstName and lastName are required fields whereas Email is an optional field.

public record SignUp(string firstName, string lastName)
    public string Email{get; init;}

Construction could look like the following, with Email unspecified.

SignUp signUp= new("Sukhpinder", "Singh");

And with Email specified.

SignUp signUp= new("Sukhpinder", "Singh")
    Email = true

Non-destructive record mutation

Immutability gives notable advantages, but you will instantly find a case where you need to mutate a record.

How to do that without giving up on immutability?

The with expression answers the need. It facilitates formulating a new record in terms of a current record of the same type.

Specify the new values that need to be added or updated whereas all other properties are copied from the current record.

Let’s transform the first name to lower-case.

SignUp signup= new("sukhpinder", "singh", "email");
SignUp signupLowerCase= signup with {
   firstName= signup.firstName.ToLowerInvariant()

We can check that with has done what we expect using the built-in ToString() override.


This code produces the following output.

SignUp{firstName = "Sukhpinder",lastName= "singh", Email= "email"}
SignUp{firstName = "sukhpinder",lastName= "singh", Email= "email"}

Record inheritance

Let’s extend the signup record to extend to google signup record.

public record SignUp(
   string firstName,
   string lastName,
   string Email

New google signup looks like with inheritance.

publuc record GSignup(string firstName,string x):SignUp(firstName){
   public string googleProperty{get;init;}

I have a new property x of type string and also a new optional parameter named googleProperty. The firstName is inherited from Signup record.

Thank you for reading. I hope you like the article..!!

#Csharp #DotnetCore #Dotnet #Programming #Csharp9

Recent Posts

See All

Design Pattern – Adapter

#Aspnetcore #AdapterDesignPattern #Csharp #DesignPatterns #Dotnet According to Gang of Four, the Adapter Pattern converts the interfaces of a class into interfaces that the client requires. In other w