Record: a modern way to describe data in C#

Everyone who works with high-level object-oriented languages knows that the basic way to describe a type is with a class (this name exists in C#, C++, Kotlin, and Python). Typically, an object created this way lives on the heap.

For small objects and for memory optimisation in the C#/C++ family, there is struct. Such an object is created on the stack, uses value copying and comparison, and does not support inheritance.

And now — fairly recently (during the COVID era, starting with C# 9) — another construct appeared to describe data: record.

Actually, the idea of treating data as values has existed for a long time — but now the language gained a simple way to declare it: syntactic sugar.

Main advantages:

  • Immutable by default — values are provided once at creation time.
  • Value-based equality — objects are considered equal if all their fields match.
  • Easy cloning with modifications — via the with syntax.
  • Suitable for DTOs (data transfer objects), configurations, events, filters, and other data objects.

Here is how it might look:

record UserDto(string Name, string Email, int Age);
var user1 = new UserDto("Alice", "alice@example.com", 30);
var user2 = user1 with { Age = 31 };  // new object, original unchanged

This is useful when you want to store data without unnecessary duplication (and you may well have faced situations where you needed to ensure you didn’t accidentally create a lot of objects after data manipulation).

For example:

  • You can store immutable settings:
record AppSettings(string Theme, int MaxItems);
var settings = new AppSettings("Dark", 100);
var updatedSettings = settings with { MaxItems = 200 };
  • Create events or messages:
record OrderPlaced(int OrderId, string Customer, decimal Amount);
var evt = new OrderPlaced(123, "Bob", 99.99m);
  • Use lightweight comparable objects:
record Filter(string Field, string Value);
var f1 = new Filter("Name", "Alice");
var f2 = new Filter("Name", "Alice");
Console.WriteLine(f1 == f2); // true — value-based comparison

No need to implement Equals, GetHashCode, etc.

Summary — how record differs from class and struct:

CLASS: copying by reference, comparison by reference, mutability: mutable, inheritance: yes.

STRUCT: copying by value, comparison by value, mutability: mutable or readonly, inheritance: no.

RECORD: copying by value, comparison by value, mutability: immutable, inheritance: no.

I hope this introduction to record will be useful if this is new to you.

Leave a Reply

Your email address will not be published. Required fields are marked *