Все, кто работает с объектно-ориентированными языками высокого уровня, знают, что базовый способ описания типа — class (такое название есть и C#, и в C++, и в Kotlin, и в Python). Обычно объект создаётся в динамической памяти (heap).
Для небольших объектов и оптимизации работы с памятью в семье C#/C++ есть struct. Этот тип объекта создается в стэке, копирование и сравнение по значению, наследование не поддерживается.
И вот, сравнительно недавно (во времена КОВИДа, версия C# 9) появилась ещё одна сущность для описания данных — record.
На самом деле, такая работа с данными существует давно, но в языке теперь имеется простой способ описания, «синтаксический сахар».
Его основные преимущества:
- Неизменяемость (immutable) по умолчанию — значения задаются при создании.
- Сравнение по значению — объекты считаются равными, если все их поля совпадают.
- Лёгкое копирование с изменением через
with. - Подходит для DTO (data transfer object), конфигураций, событий, фильтров и других объектов данных.
Выглядит это так:
record UserDto(string Name, string Email, int Age); // здесь мы описываем тип, как class или struct
var user1 = new UserDto("Alice", "alice@example.com", 30); // здесь делаем неизменную сущность
var user2 = user1 with { Age = 31 }; // новый объект, оригинал не меняется
Это полезно для хранения данных, без лишних копий (а Вы наверняка сталкивались с необходимостью следить, не создалось ли у Вас в памяти очень много объектов после манипуляции с данными).
Например,
— можно хранить настройки неизменными:
record AppSettings(string Theme, int MaxItems);
var settings = new AppSettings("Dark", 100);
var updatedSettings = settings with { MaxItems = 200 };
— создавать события и сообщения:
record OrderPlaced(int OrderId, string Customer, decimal Amount);
var evt = new OrderPlaced(123, "Bob", 99.99m);
— создавать легкие для сравнения объекты:
record Filter(string Field, string Value);
var f1 = new Filter("Name", "Alice");
var f2 = new Filter("Name", "Alice");
Console.WriteLine(f1 == f2); // true — сравнение по значению
// никаих Equals, GetHashCode etc.
Итак, вот главное различие с struct и class:
CLASS: Копирование по ссылке, сравнение по ссылке, мутабельность: mutable, наследование: есть.
STRUCT: Копирование по значению, сравнение по значению, мутабельность: mutable, или readonly, наследование: нет.
RECORD: Копирование по значению, сравнение по ссылке, мутабельность: immutable, наследование: нет.
Надеюсь, пригодится это знакомство с record, если это новое для Вас 🙂