Records in C# - Code Maze (2023)

In this article, we are going to discuss a new feature added in C#9, called “records”. Records offer an alternative to classes and structs and offer a number of advantages over those types that we’ll cover in this article.

To download the source code for this article, you can visit our GitHub repository.

To start off, let’s cover what records actually are, and how they differ to classes and structs.

What Are Records?

Records are reference types, just like classes. The main way they differ from classes is when it comes to equality.

Two records are equal if:

  • Definitions are equal (e.g same number/name of properties)
  • Values in each of those definitions are equal

On the other hand, two classes are equal if:

  • The two objects are of the same class type
  • Variables refer to the same object

In other words, records usevalue-based equality, whilst classes usememory-based equality.

Now that we understand what records are at a high level, let’s dig into how we can actually use them.

Basic Syntax

To declare a record, we use the recordsyntax, in place of where we would use class or struct:

public record Person

Using the above syntax, we are implicitly using record classes. We can be explicit by using the class keyword:

(Video) T2S5 John Kilmister - Maze Generation for Fun in C#

public record class Person

Alternatively, we can use a record struct:

public record struct Person

When we mark our class or struct as a record, the compiler will generate a bunch of methods for our convenience such as overriding the Equals method and several operators. These will come in handy when it comes to equality, which we will discuss in the next section.

Equality

As we mentioned earlier, two records are equal if the definitions and the values are equal.

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

Let’s look at an example, by creating a simple record:

public record Person{ public Person(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public string LastName { get; set; } public string FirstName { get; set; }}

Now let’s create a few records and then see if they are equal:

public class Program{ public static void Main(string[] args) { var person1 = new Person("Joe", "Bloggs"); var person2 = new Person("Joe", "Bloggs"); var person3 = new Person("Jane", "Bloggs"); Console.WriteLine($"Person1 == Person2? {person1 == person2}"); Console.WriteLine($"Person1 == Person3? {person1 == person3}"); Console.ReadKey(); }}

The output is:

Person1 == Person2? TruePerson1 == Person3? False

As we expected, because person 1 and person 2 share the same definition and values, they are equal, whilst person 3 has a different FirstName, so it is not equal.

This behavior can be extremely useful to check if two records have changed, for example, if you’re passing a record to a different thread/process and want to see if the values have changed. This ties nicely to the next feature and benefit of records that we will discuss, being immutability.

(Video) Programming Mazes

Immutability of Records

Records are designed to be used for scenarios where immutability is key. For example, if we design a multi-threaded application where we pass objects around. They are also designed to hold data structures and not states.

There are a number of features included with records that help with this design goal.

Init-only Properties

The first one is “init-only properties”.

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

Let’s modify our Person class:

public record Person{ public string FirstName { get; init; } public string LastName { get; init; } }

We are now using the init operator to specify that the properties of the Person record can only be set during initialization.

Let’s modify our console app to now use the object initializer to set the properties:

var person1 = new Person { FirstName = "Joe", LastName = "Bloggs" };var person2 = new Person { FirstName = "Joe", LastName = "Bloggs" };var person3 = new Person { FirstName = "Jane", LastName = "Bloggs" };

If we then try to modify the FirstName property of person1, we get the following error:

CS8852: Init-only property or indexer 'Person.FirstName' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor.

Positional Records

The more concise way of presenting this behavior is by using“positional records”.

Let’s modify our Person class again:

(Video) Recursive Maze Solver

public record class Person(string FirstName, string LastName);

Now we can modify our code again to go back to the constructor method:

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

var person1 = new Person("Joe", "Bloggs");var person2 = new Person("Joe", "Bloggs");var person3 = new Person("Jane", "Bloggs");

We still get the same error if we try and change any of the properties again.

This is probably the key feature to call out. We want to capture the initial state of the data and pass it around our app, but we do not want anything modifying it in any way. If we want the record similar to the state of another record, however, we can use the special cloning features of records, which we’ll discuss in the next section.

Cloning Records

When it comes to cloning in .NET, there are usually two possibilities:

  • Shallow cloning (the members of the copied object refer to the same object as the original object)
  • Deep cloning (the members of the copied object are completely separate)

With regular classes, to do a shallow clone we can use the MemberwiseClone() method that is inherited from the base Object class. To do a deep clone, we would need to implement ICloneable and do it ourselves (perhaps, with some kind of serialization).

Built into records, there is a special with operator we can use:

var person4 = person3 with { LastName = "Doe" };Console.WriteLine(person4);

In the above example, we are saying that we would like a copy of the person3 object, but with the LastName property set to “Doe”, and all other properties the same. This syntax can come in very handy when we want to create copies of records with only minimal differences.

Behind the scenes, the compiler is doing what is called “non-destructive mutation”, where the properties of the original record are copied to the new record, but the original record is not mutated in any way, keeping with the goal of immutability.

Let’s check the output:

Person1 == Person2? TruePerson1 == Person3? FalsePerson { FirstName = Jane, LastName = Doe }

The result is what we expect: the LastName has been set to what we specified, but the FirstName has been based off the person3 record. One other thing you might notice is the built-in formatting display. We didn’t have to create a custom .ToString() method to make it nice and readable, records do this for us! This is a very handy feature that will save us lots of time (and code).

(Video) Intro to C#: 22 - Creating an Explorable Maze

Inheritance

Just like with normal classes, records support inheritance. Let’s create a derived Employee record:

public record Employee(string FirstName, string LastName, string Job) : Person(FirstName, LastName);

The syntax is very similar to regular class inheritance. The properties we inherit from the base record pass to the constructor, and the derived class has its own properties as well.

Next, let’s modify our class to now instantiate our derived class:

var person1 = new Employee("Joe", "Bloggs" , "Firefigher");var person2 = new Employee("Joe", "Bloggs", "Teacher");var person3 = new Employee("Jane", "Bloggs", "Programmer");

If we run our app, we’ll see the ToString() built-in formatted we mentioned earlier automatically picks up the new property, without us changing any code:

Employee { FirstName = Jane, LastName = Doe, Job = Programmer }

When to Use Records

We’ve discussed a lot of the features of records, and syntactic sugar aside, it should be clear there are a number of benefits, and it should be a first-class citizen in our programming toolbelt. We will not compare records vs classes vs structs, as that is outside of the scope of this article and an extensive topic, but in terms of performance let’s treat classes and records (reference types) the same, whilst structs (value types) are for simple types where no inheritance of complex domain modeling is required. So, let’s focus on the classes vs records use cases.

Immutability

The main advice for records over classes so far is when we want to have immutable objects that don’t need to change state, and are passed around different threads/classes. An obvious example here would be a DTO or an input model. These are one-way objects that get properties set, and are passed along. These are now perfect candidates for records.

Concise Code

Furthermore, we’ve seen how simple and concise writing records are. Less code means better code and a smaller codebase, which means easier maintenance. The fact that we can declare an object with auto-initialized properties and built-in formatting with a single line is a very enticing proposition.

Wanna join Code Maze Team, help us produce more awesome .NET/C# content and get paid? >> JOIN US! <<

Changing Our Mindset

Finally, another way to look at things is flipping the question to: “when wouldn’t we use a record?”. Immutability is a good thing and will save a lot of bugs, so having a mindset of “records-first”, and going to classes when a mutation is required is a good idea. If we build a DDD-like application where state and behavior are modeled on the objects, then classes are a good choice. But for simple APIs where we bind to objects, pass to data layers, map to objects and return responses, records are perfect as no mutation is required.

Conclusion

In this article, we have provided a brief introduction to the new records type in C#, discussed the syntax and basic features, and reviewed the use cases for applying them to our applications. Records are not a ‘small’ new feature, they are a brand new top-level type new to the framework, and given their simplicity and number of advantages over other types, let’s expect to see a lot more of them in codebases moving forward.

FAQs

How to use records in C#? ›

Beginning with C# 9, you use the record keyword to define a reference type that provides built-in functionality for encapsulating data. C# 10 allows the record class syntax as a synonym to clarify a reference type, and record struct to define a value type with similar functionality.

What are records in C#? ›

A record is a reference type and follows value-based equality semantics. You can define a record struct to create a record that is a value type. To enforce value semantics, the compiler generates several methods for your record type (both for record class types and record struct types): An override of Object.

Are records immutable C#? ›

Record Types are Not Immutable by Default

You can easily create a mutable record type. As I discussed in the previous tutorial on init-only properties in C# 9, we can make the record type immutable by swapping out the set accessor on the properties with the new init accessor.

Is Code Maze good? ›

Code Maze is an essential tool for any professional C# developer. It has transformed how I develop MVC systems. I have produced several systems in the last 6 months all of which have been very successful.

What are records with example? ›

Examples include documents, books, paper, electronic records, photographs, videos, sound recordings, databases, and other data compilations that are used for multiple purposes, or other material, regardless of physical form or characteristics.

What is uses of records? ›

Their purpose is to provide reliable evidence of, and information about, 'who, what, when, and why' something happened. In some cases, the requirement to keep certain records is clearly defined by law, regulation, or professional practice.

What are the three types of records? ›

The following sections will provide general guidance on the disposition of 4 types of records:
  • Temporary records.
  • Permanent records.
  • Unscheduled records.
  • Records on legal hold.
Dec 15, 2021

What Are records in coding? ›

In computer science, a record (also called a structure, struct, or compound data) is a basic data structure. Records in a database or spreadsheet are usually called "rows". A record is a collection of fields, possibly of different data types, typically in a fixed number and sequence.

What is the difference between records and class in C#? ›

The main difference between class and record type in C# is that a record has the main purpose of storing data, while class define responsibility. Records are immutable, while classes are not.

How do you use art records? ›

The following are a few options to consider to use vinyl records as wall art.
  1. Frame your records either by themselves or with their album covers. ...
  2. Create a giant wall mural with paint. ...
  3. Smash albums to bits. ...
  4. Treat them like a painting. ...
  5. Arrange the album covers in a collage pattern. ...
  6. Stick them in the oven.

How do you decorate with records? ›

Mount Records Directly onto The Wall
  1. Use indoor mounting tape as adhesive to mount them onto the wall (we recommend you test out where you'd like the placement to be by using painter's tape first)
  2. Drill the center of the vinyl record onto the wall.
  3. Hook the back of the album cover onto the wall.

Videos

1. Maze Mind Game - C# Program with Input and Output
(Mark Vincent Rabe Leaño)
2. MM 2020-2021 Lecture 5: Maze Solving
(UCLA IEEE)
3. Repository Pattern In ASP.NET Core Web API
(Code Maze)
4. How To do Assignment 3 Maze Implementation
(Prof Ross)
5. Project Minotaur - C# Labyrinth Solving Algorithm
(Natiiix)
6. C# Maze Game Tutorial - Part 1
(Antony Lloyd)
Top Articles
Latest Posts
Article information

Author: Msgr. Benton Quitzon

Last Updated: 03/02/2023

Views: 5804

Rating: 4.2 / 5 (43 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Msgr. Benton Quitzon

Birthday: 2001-08-13

Address: 96487 Kris Cliff, Teresiafurt, WI 95201

Phone: +9418513585781

Job: Senior Designer

Hobby: Calligraphy, Rowing, Vacation, Geocaching, Web surfing, Electronics, Electronics

Introduction: My name is Msgr. Benton Quitzon, I am a comfortable, charming, thankful, happy, adventurous, handsome, precious person who loves writing and wants to share my knowledge and understanding with you.