Ответ
record и struct в C# предназначены для моделирования данных, но имеют принципиальные различия в поведении и предназначении.
Record (обычно record class)
- Тип: Ссылочный тип (по умолчанию —
record class). Хранится в управляемой куче (heap). - Неизменяемость: Создан для неизменяемых (immutable) данных. Свойства инициализируются при создании и не могут меняться (при использовании позиционного синтаксиса или
init-сеттеров). - Сравнение по значению: Автоматически генерирует методы
Equals,GetHashCode()и операторы==/!=, которые сравнивают значения всех свойств, а не ссылки. - Другие фичи: Встроенная поддержка
ToString()с выводом свойств, деконструкции (Deconstruct) и копирования с модификацией (withexpressions).
public record Person(string Name, int Age); // Неизменяемый record
var person1 = new Person("Alice", 30);
var person2 = new Person("Alice", 30);
Console.WriteLine(person1 == person2); // True (сравнение по значению)
Console.WriteLine(person1); // Person { Name = Alice, Age = 30 }
var person3 = person1 with { Age = 31 }; // Неизменяемое копирование
Struct (значимый тип)
- Тип: Значимый тип (value type). Хранится в стеке (stack) или внутри родительского объекта. Копируется по значению при присваивании.
- Изменяемость: По умолчанию изменяем (mutable), если не объявлен как
readonly struct. - Сравнение по значению: Не генерирует логику сравнения автоматически. По умолчанию используется
ValueType.Equals, который работает через рефлексию и медленно. Для производительности нужно реализовыватьIEquatable<T>и переопределятьEquals/GetHashCodeвручную. - Ограничения: Не может иметь конструктора без параметров (до C# 10), не поддерживает наследование.
public struct Point
{
public int X;
public int Y;
// Нет автоматического сравнения по значению!
}
var point1 = new Point { X = 5, Y = 10 };
var point2 = point1; // Копирование значения
point2.X = 20; // Изменяется только копия
Ключевой выбор:
- Используйте
recordдля неизменяемых моделей данных, DTO, где критично сравнение по значению и нужна встроенная функциональность (ToString,with). - Используйте
structдля небольших (менее 16 байт), часто создаваемых и копируемых объектов, где важна производительность и размещение в стеке (например, координаты, ключи словарей). Для неизменяемых структур объявляйтеreadonly struct.