Quite often in our architectural designs we tend to use DTOs. If you have never heard of a DTO it basically stands for Data Transfer Object. It is meant to describe a class with no bussiness logic whatsoever included in it. Only to hold different types of data and pass it around. In many cases these DTOs only include readonly properties and fields internally. Very often, writing the code for these classes feels like writing a lot of boilerplate code.

Well here is where C# 8.x is coming to simplify the process of creating these classes by introducing Records.



Just to be clear, this was initially planned for C# version 8 but due to other more important features and the complexity of this feature it has been postponed for a point version with unclear path if it will be in 8.1 or 8.2 etc

The records syntax is basically letting the compiler do all the work for us and produce that code without us writing it. Unlike code snippets where we just use a shortcut key to generate a template of code for us to fill in, the new syntax is simply telling the compiler the type of class we want, and the compiler generates it for us. For example we could have the following line of code:

public class Person(string Name, string Surname, string Address, DateTime DateOfBirth);

This simple line of code is expanded to a much larger class that also implements IEquatable

using System; public class Person: IEquatable { public string Name { get; } public string Surname { get; } public string Address { get; } public DateTime DateOfBirth { get; } public Person(string Name, string Surname, string Address, DateTime DateOfBirth) { this.Name = Name; this.Surname = Surname; this.Address = Address; this.DateOfBirth = DateOfBirth; } public bool Equals(Person other) { return Equals(Name, other.Name) && Equals(Surname, other.Surname) && Equals(Address, other.Address) && Equals(DateOfBirth, other.DateOfBirth); } public override bool Equals(object other) { return (other as Person)?.Equals(this) == true; } public override int GetHashCode() { return (Name.GetHashCode() * 17 + Surname.GetHashCode() + Address.GetHashCode() + DateOfBirth.GetHashCode()); } public void Deconstruct(out string Name, out string Surname, out string Address, out DateTime DateOfBirth) { Name = this.Name; Surname = this.Surname; Address = this.Address; DateOfBirth = this.DateOfBirth; } public Person With(string Name = this.Name, string Surname = this.Surname, string Address = this.Address, DateTime DateOfBirth = this.DateOfBirth) => new Person(Name, Surname, Address, DateOfBirth); }

As you can see, the properties of the Record are readonly (or get only, to be exact) and can only be initialized from a constructor. In addition, value equality and correctly overrides GetHashCode method for use in hash-based collections such as Dictionary and HashTable.

Apart from this, we can see that Deconstruct is also implemented so we can simply deconstruct an instance of this class with a syntax a lot similar to the ValueTuple like the following:

var (name, surname, address, dateOfBirth) = person;

The last thing we see in the generated class is the With method. This is also a new introduction to the language. For both immutable and mutable classes the with expression can produce a new instance with a single or more values changed like the following.

var bornYesterday = person.With(DateOfBirth: DateTime.Now.AddDays(-1));

All of this with one line of code. Simpler, cleaner, smoother.