Introducing C# 9: Records
C# 9 introduces Init-only properties that allow to make individual properties immutable. C# 9 introduces another great feature that enable a whole object to be immutable and make it acting like a value: Records. Let’s see in this article how Records work. Unlike the previous announcement from Microsoft (https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/), data class keywords become now record keyword.
C# 9 Introduces a new keyword: record keyword. record keyword makes an object immutable and behave like a value type. To make the whole object immutable you have to set init keyword on each property if you are using an implicit parameterless constructor:
The important thing to know here with Records is that members are implicitly public if you don’t precise it. Then the following class declaration is similar to the previous above:
Records introduce also public init-only auto-property (if you don’t to use explicitly private fields) which is a shorthand of the previous declaration (same meaning):
We might want sometimes create new a object from another one because some property values are identical only one change, unfortunately your object is immutable. with keyword fixes that. It allows you create an object from another by specifying what property changes:
On that point Records work like Structs, these last override the virtual Equals method to enable value-based comparison, which means each property will be compared with a value-based approach. You already have probably noticed that ReferenceEquals method won’t work (always false), because it compares two same objects (reference-based comparison).
Constructors and deconstructors are allowed in Records. That’s good ! 🙂
But C# 9 brings a shorter syntax (Records only) named Positional Records, that allows a shorter syntax by a specific position of members:
As you may noticed, this very short syntax makes Name and CategoryId public init-only auto-properties, in other words, this “one line syntax”, makes the record immutable, and their value assignment is determined by their position. Construction (by position) and deconstruction (by position) will work fine with that syntax you already know with previous C# releases.
With-expressions and inheritance
First, inheritance is definitely supported by records.
Secondly, Records hide a clone method thats copy the whole object, then, with with expression, if you store a child object to a parent object variable, the type and the content will be preserved:
Example of a Book class that inherits from Product class:
Here is now what happen during after the assignment:
newProduct is finally a book: Microsoft gave the explanation: “Records have a hidden virtual method that is entrusted with “cloning” the whole object. Every derived record type overrides this method to call the copy constructor of that type, and the copy constructor of a derived record chains to the copy constructor of the base record. A with expression simply calls the hidden “clone” method and applies the object initializer to the result.” Source here.
Value based comparison and inheritance
C# 9 Records introduce EqualityContract. Records have a virtual protected property named EqualityContract (and every derived record overrides it) to ensure that two differents kind of objects are comparable in the same way whatever which object is compared to another one regarding the order. Example:
product2 “might think” product1 is the same because it will compare shared properties (Name and CategoryId), but product1 might think product2 is different because there is a missing property (ISBN).
EqualityContract is there to “arbitrate a consensus”, then product1.Equals(product2) and product2.Equals(product1) must both return false;