Records
Records can be stored on a heap or a stack:
Depending on the choice as above, the compiler will transform the record into either a class or a struct (in a process called the lowering). Record is just s “sugar syntax” in .NET.
Records are useful when we’re dealing with classes that just carry information and do not have any logic/methods (DTOs).
Features
Printing
Printing an instance of a record by default prints its content. An instance of a class would print its type.
Records printing behavior may be overridden just like in a normal class.
Equality
Class instances (unless explicitly coded otherwise) will not be equal even if all properties have the same values. Equality is checked by reference.
In the case of records, an equality check compares the values of the properties.
The with
operator
Records may be copied (by value) with some changes to original values like this:
Deconstructing
A bit similarly to JS, we can extract some values from records:
Intermediate Language
To better understand the difference between a class and a struct, let’s compare IL generated for an empty class and record.
Class
The generated IL is really simple, and it really just corresponds to the provided C# code. The only thing added is a constructor.
Record
That’s a huge difference. An empty record results in lots of code being generated. All this code is a result of features that records support:
- equality logic (you can see a few equality-related methods)
ToString
override - interesting point is how the{
character is added viaAppend(string)
override ofStringBuilder
, while the closing bracket (}
) usesAppend(char)
(with value 125 representing}
)- cloning